Library / SDK
ivopetkov/html5-dom-document-php avatar
ivopetkov/html5-dom-document-php

html5-dom-document-php: DOMDocument that follows HTML5 rules

A better HTML5 parser for PHP.

600 stars43 forksPHPMIT

At a glance

What is it?
HTML5DOMDocument extends the native PHP DOMDocument with the parsing behaviour HTML5 requires, so entities and void tags survive a round trip and elements gain classList, innerHTML and outerHTML.
Who is it for?
Adopt html5-dom-document-php when you parse untrusted or messy HTML in PHP and need the result to match what a browser would build, especially if you query with CSS selectors. Do not expect a full HTML5 parser implementation, since the selector engine covers a documented subset, and check the composer constraint against the PHP version your application still supports.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 124 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A DOMDocument subclass, not a new API

HTML5DOMDocument extends the native DOMDocument class and the design goal is that you should not have to learn a new API to use it. The example in the project documentation is deliberately unremarkable:

php
<?php
require 'vendor/autoload.php';

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body>Hello</body></html>');
echo $dom->saveHTML();

The class name changes, the methods do not. You still call loadHTML and saveHTML, you still get a DOMDocument back with the usual node API, and any code that type hints against the built-in class keeps working in most cases. What changes is the behaviour behind those methods, and the additions on top. The stated purpose is to fix some bugs and add some new functionality, and the list of additions is the classList property, innerHTML and outerHTML, plus a querySelector method that takes CSS selectors. That combination makes it useful in two places, in server side rendering work where a template engine produces HTML fragments, and in scraping or testing code where the input HTML is not under your control.

Entities and void tags survive the round trip

The first two fixes are about data loss, and they are the reason many people look for a library like this at all. The first is that HTML entities are preserved, which DOMDocument does not do. The second is that void tags are preserved, also not done by the native class. Both matter in a pipeline where HTML goes in, gets parsed, is modified, and is written back out. If an entity or a void element is dropped or normalised on the way through, the output no longer matches the input, and a diff between the original and the round tripped document is full of noise. A tool that reports the difference between expected and actual output, which is how a lot of server side rendering tests are written, is only useful if the parser itself is faithful. The two preservation fixes narrow the gap between the PHP document and what a browser would build from the same markup, which is the reference behaviour HTML5 describes.

CSS selectors, limited to a documented subset

The querySelector and querySelectorAll additions accept CSS selectors, and the documentation is precise about which ones are implemented. The list covers the universal selector, a tag name, a tag name with an id, an id alone, a tag with one class, a class alone, a tag with two classes, two classes alone, a tag with an attribute selector, an attribute selector alone, a selector list such as div, p, a descendant combinator such as div p, the child combinator div > p, the adjacent sibling combinator div + p and the general sibling combinator p ~ ul. That is a decent chunk of the selector syntax, but it is a fixed subset rather than a full engine, and there is no pseudo-class support in the list. The consequence is that a selector you can write in a browser is not automatically supported here, so a query with a pseudo-element or a structural pseudo-class will not behave as expected. The example shows the intended usage:

php
$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');

echo $dom->querySelector('h1')->innerHTML;
// Hello

echo $dom->querySelector('.content')->outerHTML;
// <div class="content">This is some text</div>

If your existing code already uses a selector engine, this one is a convenience rather than a replacement, and the subset list is worth reading before you rely on it.

insertHTML routes content to head or body for you

The insertHTML method is the feature with the clearest practical payoff. It lets you insert a block of HTML into a document, and it moves the parts to their proper places, so head elements are inserted in the head and body elements in the body. Without that, a naive insertion of a full html fragment tends to land in the wrong place, for example putting a script tag into the body or leaving a style element at the top of the body, and the fix is usually a pile of manual node moves. The example in the documentation inserts a fragment containing a script in the head and a div in the body, and the saved output shows the style element already in the head, the script element next to it, the existing heading still in the body and the new div after it. For a template system that assembles a page from partials, that is the difference between a one line call and a fragment of node manipulation code.

classList, innerHTML and outerHTML on elements

The remaining additions are the small conveniences that PHP's DOM has historically lacked. Element classList is supported, so you can manipulate the class attribute of an element as a list rather than by splitting and joining a string:

php
$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<div class="class1"></div>');

echo $dom->querySelector('div')->classList->add('class2');

innerHTML and outerHTML are both supported, which means you can read the content of an element or the element including its own tags. The example above shows the difference in practice, innerHTML on the heading returns the text, and outerHTML on the content div returns the div with its class attribute intact. The classList example also shows a detail worth knowing, since add returns a value that the example echoes. Reading the class attribute as a set and rewriting it as a string is the kind of code that ends up with double spaces and inconsistent separators, and having a list interface removes that class of bug. None of this is exotic, and that is the point, these are the small gaps in the native DOM that most PHP developers have written the same helper for more than once.

Composer install, repository layout and release cadence

Installation is a single Composer requirement, and the version constraint is explicit:

shell
composer require "ivopetkov/html5-dom-document-php:2.*"

The repository has an autoload.php at the top level alongside composer.json, plus a src directory for the class, a tests directory with a phpunit.xml configuration, and a docs directory. The documentation is part of the repository, at docs/markdown/index.md, and there is a docs-generator.php script at the root, which suggests the docs are produced from the source rather than written by hand and drifting. The package is published on Packagist as ivopetkov/html5-dom-document-php, and the licence is MIT. The release history is steady, with v2.10.0 on 2025-12-06, v2.10.1 on 2026-01-31 and v2.11.0 on 2026-06-21, and the last push was on the same day as the newest tag, with the repository not archived. The library is created and maintained by Ivo Petkov, and the project invites issues and pull requests.

Editorial conclusion

Adopt html5-dom-document-php when you parse untrusted or messy HTML in PHP and need the result to match what a browser would build, especially if you query with CSS selectors. Do not expect a full HTML5 parser implementation, since the selector engine covers a documented subset, and check the composer constraint against the PHP version your application still supports.

Frequently asked questions

How do I install html5-dom-document-php?

Require it through Composer with composer require "ivopetkov/html5-dom-document-php:2.*". The package is also published on Packagist under the name ivopetkov/html5-dom-document-php.

What does HTML5DOMDocument fix compared to the native DOMDocument?

It preserves HTML entities and preserves void tags, both of which the native DOMDocument does not do. It also adds insertHTML, CSS selector queries, classList, innerHTML and outerHTML.

Which CSS selectors does html5-dom-document-php support?

The documented set covers the universal selector, tag names, ids, single and double class selectors, attribute selectors, selector lists such as div, p, and the descendant, child, adjacent sibling and general sibling combinators. Pseudo-classes are not part of the listed support.

What does insertHTML do in HTML5DOMDocument?

It inserts an HTML fragment into the document and moves the correct parts to their proper places, so head elements are inserted in the head and body elements in the body, instead of the whole fragment landing in one place.

Is html5-dom-document-php still maintained?

The repository is not archived, the last push was on 2026-06-21 and the newest tag is v2.11.0 from the same day, after v2.10.1 in January 2026 and v2.10.0 in December 2025.

Official sources

  1. Issues
  2. ivopetkov/html5-dom-document-php on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ivopetkov-html5-dom-document-php.svg)](https://hysenlabs.com/projects/ivopetkov-html5-dom-document-php)

Was this useful?