Slint Reactivity
Introduction
Reactivity is a core concept in Slint. It allows you to create complex, dynamic user interfaces with far less code.
In Slint, UI elements automatically update when the properties they depend on change — without requiring manual refresh logic.
Example: Mouse Tracking and Color Change
export component MyComponent {
width: 400px; height: 400px;
Rectangle {
background: #151515;
}
ta := TouchArea {}
myRect := Rectangle {
x: ta.mouse-x;
y: ta.mouse-y;
width: 40px;
height: 40px;
background: ta.pressed ? orange : white;
}
Text {
x: 5px; y: 5px;
text: "x: " + myRect.x / 1px;
color: white;
}
Text {
x: 5px; y: 15px;
text: "y: " + myRect.y / 1px;
color: white;
}
}
How It Works
- The rectangle follows the mouse using
x: ta.mouse-x;
andy: ta.mouse-y;
. - Color changes on click:
background: ta.pressed ? orange : white;
. - Text labels automatically update to show the rectangle's current position.
This works because:
- The
TouchArea
exposesmouse-x
,mouse-y
, andpressed
properties. - When these properties change, all bound expressions are automatically re-evaluated.
- The UI updates only where dependencies have changed.
Performance and Dependency Tracking
Slint evaluates bindings lazily:
- Dependencies are registered when a property is accessed during evaluation.
- When a property changes, only dependent expressions are re-evaluated.
- This ensures high performance, even for complex UIs.
Property Expressions
Property bindings can be simple or complex:
// Tracks foo.x
x: foo.x;
// Conditional expression
x: foo.x > 100px ? 0px : 400px;
// Clamped value
x: clamp(foo.x, 0px, 400px);
You can also use functions for clarity:
export component MyComponent {
width: 400px; height: 400px;
pure function lengthToInt(n: length) -> int {
return (n / 1px);
}
ta := TouchArea {}
myRect := Rectangle {
x: ta.mouse-x;
y: ta.mouse-y;
width: 40px;
height: 40px;
background: ta.pressed ? orange : white;
}
Text {
x: 5px; y: 5px;
text: "x: " + lengthToInt(myRect.x);
}
Text {
x: 5px; y: 15px;
text: "y: " + lengthToInt(myRect.y);
}
}
Purity in Bindings
For reactivity to work correctly, bindings must be pure:
- Evaluating a property should not change any other observable state.
- The Slint compiler enforces purity in binding expressions, pure functions, and pure callbacks.
Example:
export component Example {
pure callback foo() -> int;
public pure function bar(x: int) -> int {
return x + foo();
}
}
Two-Way Bindings
Two-way bindings keep two properties in sync using <=>
:
export component Example {
in property<brush> rect-color <=> r.background;
in property rect-color2 <=> r.background;
r:= Rectangle {
width: parent.width;
height: parent.height;
background: blue;
}
}