States and Transitions
A states block declares a set of named states on an element.
Each state carries a condition and a set of property values that apply while that state is active:
export component Example inherits Window { in-out property <bool> active: true; label := Text { }
states [ active when active: { label.text: "Active"; root.background: blue; } inactive when !active: { label.text: "Inactive"; root.background: gray; } ]}A states block is a single statement inside an element’s body, written states [ ... ].
It may appear on any element — the root, a child, a sub-component’s root, or the element of a for — and each element has its own independent set of states.
An element may hold more than one states block; their entries are combined in source order.
A global may not contain a states block; doing so is a compile error.
States
Section titled “States”Each entry has a name, an optional when condition, and a brace-delimited body:
name when condition: { element.property: value; // ...}The name is an identifier local to the element.
The when clause holds an arbitrary boolean expression.
The condition may reference any property in scope, including properties of other elements (ta.has-hover).
At most one state is active at a time.
When several conditions hold, the state listed first in source order wins.
When no condition holds, no state is active and the element’s normal bindings apply.
A state written without a when clause has no condition and is therefore never selected; it only serves as a name that a transition can refer to.
Property changes
Section titled “Property changes”The body of a state is a list of property changes. Each change is a qualified name, a colon, and a value:
root.background: blue;label.text: "Active";The value is a binding expression, so it may be a single expression or a code block { ... }, and it may reference other properties.
Property changes are subject to these rules, each enforced by the compiler:
- The qualified name must resolve to a property.
An unqualified name refers to a property of the element that owns the
statesblock (backgroundis the same asroot.background). A qualified name addresses a descendant by its element id (label.text). - A name whose element id is unknown, whose member is not found, or that does not name a property is an error.
- The value’s type must be assignable to the property.
- A property initialized with a two-way binding cannot be changed in a state; doing so is an error.
While a state is active its listed properties take the state’s values; a property not listed in the active state keeps its normal binding.
Transitions
Section titled “Transitions”A transition binds animations to the entering or leaving of a state.
Transitions are declared with in, out, or in-out blocks inside the state they belong to:
export component Example inherits Window { in-out property <bool> pressed; in-out property <bool> is-enabled; text := Text { text: "hello"; }
states [ disabled when !root.is-enabled: { background: gray; text.color: white; out { animate * { duration: 800ms; } } } down when pressed: { background: blue; in { animate background { duration: 300ms; } } } ]}The three directions are:
in— animate when entering the state.out— animate when leaving the state.in-out— animate in both directions.in_outis accepted as a spelling ofin-out.
A direction block sits alongside the property changes in the state body and may be repeated; a state may hold several in, out, or in-out blocks.
Animations in transitions
Section titled “Animations in transitions”The body of a direction block contains only animate clauses; anything else is an error.
Each animate clause names one or more properties, or the catch-all *, and carries the same fields as an animation elsewhere (see Animations):
in { animate * { duration: 200ms; } animate background, text.color { duration: 100ms; }}animate *matches every property changed by the state. The catch-all is allowed only inside a transition.- The properties named must be among those changed by the state the transition belongs to; naming an unchanged property is an error.
- A property that already has an
animatebinding of its own cannot also be driven by a transition; that combination is an error.
The standalone transitions [ ... ] block from the legacy syntax is no longer supported.
Declare transitions with in, out, and in-out directly inside the state.
© 2026 SixtyFPS GmbH