Documents v0.9.0 · previews run the real runtime · experimental features are marked exp

content (DOM text)

declarationsince 0.9.0experimentalrequires runtime

On elements, a content value that reads state also becomes the element’s DOM text: a real text node, never HTML. The native declaration is kept as written.

On this page · 10 sections+

Syntax

content: var(<state>) | when(<condition>, <a>, <b>) | previous(<state>) | direction(<state>);

registry syntax: content: var(--state) | when(condition, a, b) | previous(--state) | direction(--state)

Parameters

valueone scalar that reads staterequired
Must contain var(), when(), previous() or direction(), and no url(), image-set(), gradient or attr(). Other values stay plain CSS.

Effect

No value. The element’s text node is set with Text.data: selectable, copyable and in the accessibility tree as ordinary text.

Example

cart.cssreactive
/* <span class="count">0</span> <span class="unit">items</span> */.cart { --items: state(0); }.cart .add:on(click) { --items: increment(1); }.cart .count { content: var(--items); }.cart .unit { content: when(--items == 1, "item", "items"); }
state()Function · hover any red tokenMakes each matching element the owner of an independent state with an initial value.Reference →

Correct and incorrect usage

correctGenerated content stays native

badge.cssreactive
.cart { --items: state(0); }.cart .badge::after { content: var(--items); }

A pseudo-element is not DOM text, so this is native generated content: it shows a number from a state but is not part of the document.

incorrectAn element with child elements

card.cssreactive
/* <div class="card"><h2>…</h2><p>…</p></div> */.card { --title: state("Hello"); }.card { content: var(--title); }

This compiles, but the binding never empties an element with children: at run time it gives a diagnostic and leaves the markup. Target the h2 instead.

Behavior

  • Experimental.
  • When it applies. All of these must hold: the rule targets elements (no selector in its list has a pseudo-element); the value reads state through var(), when(), previous() or direction(); it contains no image or attr(); and the stylesheet is trusted. Every other content declaration is plain CSS and is left alone: ::before { content: var(--n) }, content: "x" and content: url(a.png) keep their native meaning.
  • The native declaration is kept. Reactive CSS adds a text binding next to it. On elements, strings and numbers in content render nothing in Chromium and WebKit, so what you see is the DOM text.
  • Text only. It writes one Text node, never markup, and only into an element that is empty or holds exactly one text node. An element with child elements is never emptied; a diagnostic is given instead.
  • Yields and restores. If something else changes the text, the binding yields. When no declaration applies, the original HTML text comes back, so the markup is the fallback before the script runs.
  • Accessibility. Unlike generated content in ::before or ::after, the text is part of the document: assistive technology reads it as ordinary text, and it can be selected, copied and found with in-page search.
  • A value that resolves to an image at run time (a var() holding url()) is left to the browser.

Supported contexts

  • Elements that are empty or hold one text node.
  • Trusted stylesheets only.

Limitations

  • Not a template language and not a general replacement for textContent: one value per element.
  • Firefox is not verified: how it renders content strings on elements has not been tested.

Examples

  • Counter · API examples, runs the real runtime
  • Form mirror · API examples, runs the real runtime
Experimental · syntax may change between minor versions