bind() in state()
declarationsince 0.9.0requires runtimestate(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.
On this page · 10 sections+−
Syntax
--<state>: state(<initial>, bind(value | checked));--<state>: state(<initial>, bind(<attribute>));registry syntax: --state: state(initial, bind(value | checked))
Parameters
- bind(value)two-wayone of
- Text-like inputs and
<textarea>hold a string; number and range inputs a number or dimension; a single<select>a string, keyword or number. - bind(checked)two-wayone of
- A checkbox, with a boolean state.
- bind(<attribute>)one-way, state → attributeone of
aria-expanded,aria-pressed,aria-selected,aria-disabled,aria-hidden,aria-busy,aria-invalid,aria-checked,aria-current,aria-valuenow,aria-label,aria-valuetext,disabled,hidden,required,tabindex(0or-1) ordata-*.
Effect
No value. With value or checked, the control writes the state on input or change, and a mutation of the state updates the control. With an attribute, every change of the state is written to the owner’s attribute.
Example
/* State that the preview line reads lives on the form, the shared owner. */.signup { --greeting: state(""); --news: state(false);}/* The field also owns a two-way state of its own. */.signup input[name=name] { --name: state("", bind(value));}/* Copy the control's value up to the form at input time. */.signup input[name=name]:on(input) { --greeting: set(event(value));}.signup input[name=news]:on(change) { --news: set(event(checked));}/* The field styles itself from its own state. */.signup input[name=name]:when(--name != "") { border-color: #15803d;}.signup .greeting { content: when(--greeting == "", "stranger", "");}.signup:when(--greeting != "") .greeting { content: var(--greeting);}.signup .sub { content: when(--news, " Newsletter: yes.", "");}Correct and incorrect usage
correctReflect a toggle into aria-pressed
.toggle { --on: state(false, bind(aria-pressed)); }.toggle:on(click) { --on: toggle(); }.toggle .label { content: when(--on, "On", "Off"); }The button’s aria-pressed follows the state. If the HTML says aria-pressed="true", the state starts as true.
incorrectA sibling reading the field’s own state
.field input { --q: state("", bind(value)); }.field output { content: var(--q); }This compiles, but the output never sees --q: the state is owned by the input, and the output is not inside it. Declare --q: state("") on .field and use .field input:on(input) { --q: set(event(value)); }.
incorrectbind() as the initial value
.menu > button { --open: state(bind(aria-expanded)); }A compile error: the state needs an initial value for the case where the attribute is missing or invalid.
Behavior
- Release status. The 0.9.0 release recommendation (hardening report, section H) lists
bind(value)andbind(checked)instate()as stable, so this page does not mark it experimental. The runtime'sdescribe()still reportsexperimentaluntil the registry is updated.bind(<attribute>)has been experimental since 0.5.2. - The control is the owner. The state belongs to the control the rule matches. Only that control and its descendants can read it: a label, an output or any other sibling cannot. For a state that other elements read, declare it on a shared ancestor and copy the value up at event time with
input:on(input) { --q: set(event(value)); }, as the example does. - Initialization. A valid persisted value first; otherwise the control’s value if the user or the browser already edited it (autofill, a restored form); otherwise the initial value. The result is then written to the control.
- Typing never rewrites the field, so the caret and the selection stay. Form reset restores the initial value.
- bind(<attribute>) reflects the state into the owner’s attribute with HTML semantics: boolean attributes present or removed (never
disabled="false"), ARIA states as"true"or"false",data-*as text. A valid attribute value in the HTML initializes the state once, unless a persisted value exists. Later changes made by scripts are not read back. - The modifiers come in either order, each at most once:
state("", bind(value), persist("name"))equalsstate("", persist("name"), bind(value)). A state has onebind().
Supported contexts
- Unconditional rules only: no
@media,@supports,@container,:hover,:focusor:when(), because a binding lasts as long as the element matches. - Trusted stylesheets only.
Limitations
state(bind(aria-expanded)), abind()without an initial value, is rejected: writestate(false, bind(aria-expanded)).bind(checked)needs a boolean state;bind(value)needs a string or number state.- Never binds password, one-time-code or payment fields.
- Multiple selects, file, date and color inputs are not supported.
Examples
- Form mirror · API examples, runs the real runtime