Skip to content

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;
}
]
}
slint

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.

Each entry has a name, an optional when condition, and a brace-delimited body:

name when condition: {
element.property: value;
// ...
}
slint

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.

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";
slint

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 states block (background is the same as root.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.

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; }
}
}
]
}
slint

The three directions are:

  • in — animate when entering the state.
  • out — animate when leaving the state.
  • in-out — animate in both directions. in_out is accepted as a spelling of in-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.

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; }
}
slint
  • 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 animate binding 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