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

Attribute sync

Keep real DOM attributes synchronized with CSS state.

--attr-*toggle()experimental
Live previewreal runtime

Click the button, or Tab to it and press Enter or Space.

How it works

  • --attr-*lines 7, 8--attr-<name>: <value> writes one allowlisted HTML attribute of the matched element from a reactive value: ARIA states such as aria-expanded, aria-checked or aria-disabled, disabled, hidden, tabindex or data-*. The only custom-property namespace with DOM semantics.
  • toggle()line 4Flips a boolean state. In an :on() rule it is the mutation --open: toggle().

Real DOM attributes driven by a state. --attr-aria-expanded writes the button’s aria-expanded, and --attr-hidden adds or removes the panel’s hidden attribute. The line under the button is native CSS attr(), which prints the attribute as it is in the DOM.

Native CSS alternative

<details> and <summary> give a disclosure with no script at all, and are usually the better choice. Reactive CSS is useful when a custom button must report its state through ARIA attributes that styles cannot write.

Limitations

  • --attr-* is a reserved namespace: a custom property named like an allowlisted attribute writes that attribute. Rename existing --attr-* properties that are not meant as attributes.
  • Only an allowlist of attributes can be written (ARIA states, data-*, disabled, hidden, required, tabindex).

Implementation

2 files · 8 lines
style.cssreactive
/* ---- Reactive CSS -------------------------------------------------------------------------- */.disclosure { --open: state(false); }.disclosure .toggle:on(click) { --open: toggle(); }/* Real attributes, written by the runtime. */.disclosure .toggle { --attr-aria-expanded: var(--open); }.disclosure .panel { --attr-hidden: when(not --open); }
state()Function · hover any red tokenMakes each matching element the owner of an independent state with an initial value.Reference →

Source: site/src/catalog/api/attribute-sync/. style.css from its Reactive CSS divider; the layout above it and the shared api.css run but are not shown.

Related

Live values

A value that changes on its own, every two seconds. Not a clock: the API has no wall-clock time.

live()random()

Mouse tracker

A dot that follows the pointer inside an area, moved with a transform.

mouse()

Element size

A card reads its own measured width, and its text follows.

experimentalelement():on()