Opt-in Self-Closing HTML
Write an empty HTML element once. Opt in with self-closing for this feature, or next for the current and future HTML Next family supported by the browser.
<!DOCTYPE html PUBLIC "self-closing">
<user-avatar name="Ada" />
<small />
<button />
<p>Following content</p>The family opt-in uses:
<!DOCTYPE html PUBLIC "next">HTML Feature Profiles defines both selections and the proposed HTTP response header.
The benefits of self-closing syntax
- Less repeated markup. Write
<user-avatar name="Ada" />instead of<user-avatar name="Ada"></user-avatar>. The element name appears once. - An explicit empty-element boundary. The opening tag contains everything the author supplies: its name, its attributes, and the marker that closes it. Following markup starts after that boundary.
- A familiar spelling in native HTML. JSX and Vue templates already use self-closing syntax.1 Authors could use the same notation for empty elements in HTML source without a compiler just for this syntax.
Evidence for these benefits
The shorter spelling and explicit closing marker are properties of the syntax. JSX and Vue demonstrate existing authoring practice and familiarity. No study of authoring speed, readability, or error rates is reported.
The insight: read once, place separately
HTML already recognizes the slash in <small/>, but ordinarily leaves small open. Simply closing it in the parser can change whether later characters become text or executable markup.
This proposal separates reading the source from placing its nodes. The source reader retains HTML's existing interpretation. A second builder places eligible self-closing elements using normal opening-and-closing actions. Every result is checked against what the source reader actually recognized.
<nav><nav /></nav><p>Outside both navs</p>
<table><tr><td /><td>Second cell</td></tr></table>The inner nav and first table cell are empty. The paragraph follows both navs; the table has two cells. Ordinary wrappers, formatting elements, custom-element hosts and table rows/cells share this behavior.
How it addresses the text-to-markup objection
<div/><svg></div><style><img src=x onerror="attack()"></style></svg>Removing div from the source reader too early can change SVG recovery and turn the apparent image into markup. This proposal retains that recovery entry: the later closing div exits SVG, the following style is HTML, and its contents remain text.
The placement builder receives that text as text. A conflicting placement is rejected in favor of the recognized HTML recovery. The protection is part of parsing: only elements the source reader recognized may appear, with their original namespace, attributes and protected contents.
A small set of understandable boundaries
Text-reading starts such as script/style/textarea, template owners, form/select contexts and document scaffolding retain their ordinary closing behavior. Each owns a reading or construction boundary that the source reader needs. Table rows and cells participate in the shorthand.
For example, <script /> opens a script and still requires </script>. The boundary table explains the categories and concrete reasons. Malformed input follows checked recovery; ordinary authored shorthand follows normal empty-element placement.
What the evidence establishes
| Question | Evidence and limit |
|---|---|
| Does ordinary shorthand behave as authors expect? | 4,000 structured authoring cases and 1,000 table cases match explicit empty pairs, including nested same-name wrappers and formatting. This is finite coverage. |
| Can the output introduce an element the source reader rejected? | Both placement paths check source identity, namespace, attributes and protected context. A checked abstract theorem establishes source authorization for the selection rule; it does not verify the JavaScript or HTML parser. |
| Do the retained security examples stay inactive? | 120,000 generated comparisons, 20,504 token-checkpoint audits and 16 targeted cases per browser adapter engine pass. The tested text/template attacks create no active image or observed attack request. |
| Is this implemented in a native browser parser? | Not yet. Chromium, Firefox and WebKit supply DOM/execution/resource behavior through a shared parse5 adapter. Native integration remains required. |
The suite also passes 88 component and placement tests. Results, reproduction and limits →
Status and review
This is a proposed source-authorized placement algorithm. Its retained counterexamples and recovery checks are part of the evidence available for review.
Native integration, form association, declarative shadow-root ownership, modules and scheduling, encoding restarts, speculative loading and independent implementer review remain required. The current results support review of this candidate, not a claim that every browser security concern is resolved.
HTML Feature Profiles owns opt-in selection and explicit API options. Flexible HTML Nesting remains a separate proposal. Earlier self-closing and opt-in proposals are prior art.45
Read the proposal
Independent Stage 0 draft. Experimental results are scoped evidence, not production support or a universal security proof.
Sources
Sources and prior art
- React, Writing Markup with JSX, and Vue, self-closing tags.
- WHATWG HTML, elements and start tags.
- WHATWG HTML, trailing solidus on non-void elements and self-closing start-tag state.
- WHATWG HTML, #721: HTML should support self-closing tags in general, including compatibility, XML, and opt-in discussion.
- WHATWG HTML, #9491 sanitizer-mismatch example and concerns about parsing-mode switches at a distance.
- W3C, XML 1.0 external identifiers, for the historical distinction between public names and URI-based system identifiers.
- WHATWG HTML, initial insertion mode, after DOCTYPE name, fragment parsing, and current doctype syntax.