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

API Reference

reference

Every shipped Reactive CSS feature in 0.9.0, grouped by what it is. The machine-readable source is ReactiveCSS.describe(), which returns the same data with syntax, parameters and status.

Note · Version 0.9.0

This reference describes Reactive CSS 0.9.0. Reactive CSS is not standard CSS: its runtime reads these extensions from your stylesheets and interprets them. 0.9 adds event rules with :on(), state mutations, event(), drag gestures, bind() and persist() in state(), --attr-*, content as DOM text and :blur. The reference lists the 0.9 syntax only. The 0.8 declarations keep working; their pages are listed under Legacy 0.8.x compatibility.

Note · Status labels

Features marked exp are experimental: persist(), content as DOM text, drag gestures and the drag fields of event(), the --attr-* namespace, typed(), element(), the attr(), pick() and split() expressions, focus:, prevent() and state(…, bind(<attribute>)). wave() was removed in 0.5.0.

:on() and its mutations, bind(value) and bind(checked) in state(), :blur, and the pointer, keyboard and form fields of event() are shown as stable, following the 0.9.0 release recommendation, although the runtime’s describe() still reports them as experimental. Everything else is stable.

State

NameKindDescriptionStatus
state()FunctionMakes each matching element the owner of an independent state with an initial value.since 0.2
persist()DeclarationKeeps a state across reloads, in localStorage or, for the tab’s session, in sessionStorage, under a key you choose.since 0.9.0 · exp
typed()FunctionRegisters a custom property with a type, so it animates and computes as that type.since 0.3 · exp

Events

NameKindDescriptionStatus
:on()RuleAn event rule: when the event happens on the matched element (or inside it, for bubbling events), the rule’s state mutations run. The cascade picks one winning mutation per state, per trigger and per element.since 0.9.0
event()ExpressionInside a mutation of an :on() rule: one field of the current event, such as event(local-x), event(key) or event(value), read once as a typed value.since 0.9.0
:on(drag)RulePointer drag gestures as event rules: :on(drag) runs on every move, drag(start), drag(end) and drag(cancel) at the edges. event(x) and event(y) give positions that continue across drags.since 0.9.0 · exp
prevent() and stop()ActionEvent modifiers for :on(): prevent() cancels the browser's default for the event, stop() ends the event at the element so ancestors do not see it.since 0.7.0 · exp
outside()TriggerAn event for :on() that happens outside the matched element: a click, a pointer press or focus moving elsewhere on the page.since 0.3

Actions

NameKindDescriptionStatus
set()ActionSets a state to a value. In an :on() rule it is a mutation of the state on the left, --x: set(5), with typed expressions.since 0.2
toggle()ActionFlips a boolean state. In an :on() rule it is the mutation --open: toggle().since 0.2
increment()ActionAdds a step to a number or dimension state. In an :on() rule it is the mutation --count: increment(1).since 0.2
decrement()ActionSubtracts a step from a number or dimension state. In an :on() rule it is the mutation --count: decrement(1).since 0.2
cycle()ActionMoves a state to the next value in a list, wrapping around. In an :on() rule it is the mutation --mode: cycle(light, dark).since 0.3

DOM Integration

NameKindDescriptionStatus
bind() in state()Declarationstate(v, bind(value)) and state(v, bind(checked)) keep a form control and its own state equal in both directions. bind(<attribute>) reflects a state into one of its owner’s attributes.since 0.9.0
--attr-*Declaration--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.since 0.9.0 · exp
content (DOM text)DeclarationOn 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.since 0.9.0 · exp
focus:DeclarationMoves focus to the matched element when its value goes from false to true because of a user action. In 0.9 this declaration is the focus request: focus: when(--open).since 0.6.0 · exp

Conditions

NameKindDescriptionStatus
when()FunctionPicks one of two values from a condition. Boolean conditions compile to native if() where supported.since 0.2
:when()SelectorMatches elements for which the condition is true, with states resolved from that element.since 0.2

History

NameKindDescriptionStatus
previous()FunctionThe value of a state before its last effective change.since 0.3
direction()FunctionWhether the last change of a number or dimension state went up, nowhere or down.since 0.3
:changed()SelectorMatches briefly after an observed change of the nearest state, until the animations it started have finished.since 0.3

Selectors

NameKindDescriptionStatus
:nth-var()SelectorMatches the sibling whose one-based index equals the integer value of a custom property or state, read on the parent.since 0.1
:just-checkedSelectorMatches a checkbox or radio after an observed unchecked → checked change, until its next change.since 0.1
:just-uncheckedSelectorMatches a checkbox or radio after an observed checked → unchecked change, until its next change.since 0.1
:blurSelectorMatches an element from a genuine focus loss until it is focused again. Unlike :not(:focus), it never matches on page load.since 0.9.0

Values

NameKindDescriptionStatus
random()FunctionA random value between min and max. The browser’s native random() handles the calls it supports; Reactive CSS runs the rest, and rolls a new value at each event inside a mutation.since 0.1
pick()FunctionOne of its values at random, per element.since 0.1
live()FunctionRe-evaluates an expression on an interval.since 0.1
on()FunctionRe-evaluates an expression each time an event fires on the element. The value function, not the :on() event rule.since 0.1
mouse()FunctionThe pointer position in px, in viewport coordinates or relative to the element.since 0.1
visible()Function1 while at least the threshold of the element intersects the viewport, else 0.since 0.1
viewport()FunctionCompiles to native 100dvw or 100dvh. No runtime.since 0.1

Geometry & motion

NameKindDescriptionStatus
element()FunctionThe element’s own border-box width or height in px, from one shared ResizeObserver.since 0.4 · exp

Expressions

NameKindDescriptionStatus
attr()ExpressionIn state() and in mutations: reads an HTML attribute into a state. Everywhere else attr() is the browser’s native function.since 0.5 · exp
pick() in state()ExpressionIn state() and in mutations: one value at random each time the expression is evaluated, once per owner in state(), at every event in set().since 0.5 · exp
split()ExpressionSplits a string into a list, only as the single argument of pick(). Entries are trimmed and empty entries dropped.since 0.5 · exp

Beyond CSS

  • JavaScript API: start(), stop(), refresh(), stats(), diagnostics, describe(), compile() and version, and the ReactiveCSSConfig options: see Installation.
  • Custom bundles and the reactive-css CLI (0.8.0): features, profiles, build, analyze (which also lists 0.8 syntax with its 0.9 form) and missing-feature diagnostics: see Custom bundles.

Not shipped

These are recorded in the library’s feature registry as planned, deferred, rejected or removed. None of them is available in 0.9.0. The list comes from describe().

ProposalKindStatusWhy, and what to use instead
wave()functionRemoved in 0.5Removed before beta: a convenience over native @property + @keyframes (which compose the same way: animation lists, calc(), several properties), at a measured main-thread style cost of 171-181 ms/s per 1,000 animated elements where a composited @keyframes translate costs 0. Animate translate/opacity/transform directly when possible.
history()functionPlanned or deferredNo UI case yet that previous() and direction() do not cover.
element (other element)functionPlanned or deferredDeferred: anchor-size() and container units cover the common cases natively; a scoped, nearest-owner lookup needs its own design.
spring()functionPlanned or deferredA duration does not define a spring, and following a continuously changing source needs per-frame physics in JavaScript. A transition with a linear() spring curve covers discrete changes natively.
throttle()functionPlanned or deferredNo UI case found that a frame-coalesced source plus a transition does not cover; reconsider with a concrete case.
debounce()functionPlanned or deferredSame: no concrete case yet beyond transition-delay.
map()functionRejectedNative progress() does it (clamped, reversed ranges included) in Chromium and WebKit; with --mx: mouse(x), write opacity: progress(var(--mx), 0px, 1000px).
distance()functionRejectedNative hypot() computes it from any reactive inputs.
cycle()functionRejectedNative keyframes with steps() do it without JavaScript, and the name would be confused with the cycle() action.
smooth()functionRejectedA transition on the consuming property does exactly this natively.
drag and dropactionRejectedDuplicates the platform or needs broader permissions than state changes.
physicsactionRejectedDuplicates the platform or needs broader permissions than state changes.
routingactionRejectedDuplicates the platform or needs broader permissions than state changes.
storageactionRejectedDuplicates the platform or needs broader permissions than state changes.
network requestsactionRejectedDuplicates the platform or needs broader permissions than state changes.
clipboardactionRejectedDuplicates the platform or needs broader permissions than state changes.
DOM mutation actionsactionRejectedDuplicates the platform or needs broader permissions than state changes.
animation DSLactionRejectedDuplicates the platform or needs broader permissions than state changes.
Experimental · syntax may change between minor versions