Start here

HTML Next in plain terms

HTML Next is a way to build web interfaces by writing markup, not framework code. You define reusable tags, add data and behavior with a small set of attributes, and it turns into ordinary native HTML the browser already understands. This page is the plain-language tour; every section links to the precise spec.

Orientation · read this first

The one-sentence version

Take the good parts of modern component frameworks, components, reactive data, scoped styles, and express them as HTML itself, so they run natively in the browser (through a polyfill today) or compile to React, Vue, or Svelte, with no build step required and no eval().

<!-- You write this -->
<x-button variant="solid">Save</x-button>

<!-- It becomes a real native button (no wrapper, no shadow root) -->
<button data-component="x-button" data-variant="solid">Save</button>

A component is not a class or a function. It is a piece of markup, treated as data. The browser (or the polyfill) reads it and produces real elements, so what ships is a plain <button> with native focus, forms, and accessibility intact, plus a data-component stamp saying where it came from.

The pieces, at a glance

HTML Next is not one big feature; it is a handful of small ones, each its own module. In plain terms:

ModuleIn plain terms
ComponentsDefine a reusable tag with <template component>. Its interface (props) and non-visual declarations live in a <defs> region; below that is the markup it renders.
TemplatingControl flow as attributes that survive the HTML parser: $if (show or not), $each (repeat), $match (pick one), $value/$html (output text or safe markup).
ExpressionsA small, typed, no-JavaScript expression language for the values in those attributes, with predictable rules for missing data and equality (it never throws).
Bindings & eventsSet values with :attr, two-way with bind:, react to events with on:, toggle a class or style with class:/style:.
ReactivityDeclare local <state>, derived <computed> values, and external <data> reads. Change a value and only what depends on it updates.
TypesProps default to strings but can borrow richer web-native types from CSS (<length>, <color>, enums, lists, structured JSON).
ValidationThe browser's own form-validation model, generalized so any typed value can be valid or invalid, styled with the native :user-invalid.
Style scopingA component's <style> applies to that component, using CSS @scope, scoping without the isolation cost of a shadow root.
The JavaScript layerThe escape hatch. When behavior genuinely needs code (a timer, a chart library), a separate ES-module controller attaches to the component. Definitions stay script-free.

How it fits together

Two ideas hold the whole thing up:

  • Declarative by default, code only when needed. Most of an interface, structure, data, styling, is markup with no script. Imperative JavaScript is a deliberate, separate layer you reach for only when there is no declarative way, and even then the component definition stays pure data.
  • Everything joins by tag. A definition and, if it has one, a controller both register under the same tag name in a registry, the exact way the platform's own custom elements join a tag to a class. Nothing references anything else by file path; the tag is the join.
Two ways to run it

The same source has two honest execution paths: a polyfill that lowers it to native DOM in the browser today, and converters that compile it to idiomatic React, Vue, or Svelte. Both must produce the same observable result (Targets & Equivalence).

How "done" is measured

There is no big version number. Like CSS, each module advances on its own through Levels (Level 1 is the shipping baseline), and a dated Snapshot is just a named set of modules each pinned at a Level. A feature is real when it is specified and has conformance tests, not when a number is announced.

What is solid, and what is still open

Being plain also means being honest about maturity:

Solid today

The component model, templating and control flow, the expression language and its value semantics, bindings, types, style scoping, and the shape of the JavaScript layer, all specified, and the browser-lowering and validation paths have a tested reference implementation.

Still open

Live reactive updates in the browser (a later Level), real-time data (SSE/WebSocket), routing, demand-driven lazy loading gated on reactive state, and the full converter targets. These are named as open, not hidden (details).

See it working

For complete, copy-pasteable code, one component, a component that uses another, and a JavaScript controller, see Examples. Then dive into any module above for the precise rules.