---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
title: Reactivity
description: Reactivity
---



## Purity


Slint's property evaluation is lazy and "reactive". Property
bindings are evaluated when reading the property value. Dependencies between properties are
automatically discovered during property evaluation. The property stores the
result of the evaluation. When a property changes, all dependent properties get
notified, so that the next time their value is read, their binding is re-evaluated.

For any reactive system to work well, evaluating a property shouldn't change any
observable state but the property itself. If this is the case, then the expression
is "pure", otherwise it's said to have side-effects. Side-effects are problematic
because it's not always clear when they will happen: Lazy evaluation may change
their order or affect whether they happen at all. In addition, changes to
properties during their binding evaluation due to a side-effect may result in
unexpected behavior.

For this reason, bindings in Slint _must_ be pure. The Slint compiler enforces
code in pure contexts to be free of side effects. Pure contexts include binding
expressions, bodies of pure functions, and bodies of pure callback handlers.
In such a context, it's not allowed to change a property, or call a non-pure
callback or function.

Annotate callbacks and public functions with the `pure` keyword to make them
accessible from property bindings and other pure callbacks and functions.

The purity of private functions is automatically inferred. You may declare
private functions explicitly "pure" to have the compiler enforce their purity.

```slint
export component Example {
    pure callback foo() -> int;
    public pure function bar(x: int) -> int
    { return x + foo(); }
}
```

## Bindings

The binding expression is automatically re-evaluated when properties accessed in the expression change.

In the following example, the text of the button automatically changes when
the user presses the button. Incrementing the `counter` property automatically
invalidates the expression bound to `text` and triggers a re-evaluation.

```slint
import { Button } from "std-widgets.slint";
export component Example inherits Window {
    preferred-width: 50px;
    preferred-height: 50px;
    Button {
        property <int> counter: 3;
        clicked => { self.counter += 3 }
        text: self.counter * 2;
    }
}
```

The re-evaluation happens lazily when the property is queried.

Internally, a dependency is registered for any property accessed while evaluating a binding.
When a property changes, the dependencies are notified and all dependent bindings
are marked as dirty.

Callbacks in native code by default don't depend on any properties unless they query a property in the native code.

## Two-way Bindings

Create two-way bindings between properties with the `<=>` syntax. These properties will be linked
together and always contain the same value.

The right hand side of the `<=>` must be a reference to a property of the same type.
The property type is optional with two-way bindings, it will be inferred if not specified.
The initial value of a linked property will be the value of the right hand side of the binding.
The two linked properties must be compatible in terms of input/output.

```slint
export component Example  {
    in property<brush> rect-color <=> r.background;
    // It's allowed to omit the type to have it automatically inferred
    in property rect-color2 <=> r.background;
    r:= Rectangle {
        width: parent.width;
        height: parent.height;
        background: blue;
    }
}
```