---
title: Reactivity
description: Reactivity
---

## Reactivity

Reactivity is core concept within Slint. It allows the creation of complex dynamic user interfaces with a fraction of the code.
The following examples will help you understand the basics of reactivity.

```slint playground
export component MyComponent {
    width: 400px; height: 400px;

    Rectangle {
        background: #151515;
    }

    ta := TouchArea {}

    myRect := Rectangle {
        x: ta.mouse-x;
        y: ta.mouse-y;
        width: 60px;
        height: 60px;
        background: ta.pressed ? orange : skyblue;
        Text {
            x: 5px; y: 5px;
            text: "x: " + myRect.x / 1px;
            color: white;
        }
        Text {
            x: 5px; y: 20px;
            text: "y: " + myRect.y / 1px;
            color: white;
        }
    }
}
```

As the name suggests, Reactivity is all about parts of the user interface automatically updating or 'reacting'
to changes. The above example looks simple, but when run it does several things:

- The `Rectangle` will follow the mouse around as you move it.
- If you `click` anywhere the `Rectangle` will change color.
- The `Text` elements will update their text to show the current position of the `Rectangle`.

The 'magic' here is built into the Slint language directly. There is no need to opt into this or define
specific stateful items. The `Rectangle` will automatically update because its `x` and `y` properties
are bound to the `mouse-x` and `mouse-y` properties of the `TouchArea` element. This was done by giving
the `TouchArea` a name to identify it `ta` and then using the name in what Slint calls an `expression`
to track values. It's as simple as `x: ta.mouse-x;` and `y: ta.mouse-y;`. The mouse-x and mouse-y properties
are built into the `TouchArea` and automatically update as the cursor moves over them.

The `TouchArea` also has a `pressed` property that is only `true` when the cursor is pressed or clicked down.
So the ternary expression `background: ta.pressed ? orange : white;` will change the background color of the `Rectangle`
to orange when `ta.pressed` is true, or white when it isn't.

Similarly the 2 text items are updating by tracking the rectangle's `x` and `y` position.

## Overwritten Bindings

Bindings in Slint are only active as long as the property is assigned using a binding expression (`x: other.value`) or a two-way binding (`<=>`).
If a property's value is later changed using an imperative assignment in code (e.g. `foo.bar = 42;`), the original binding is broken.
From that point on, the property will no longer react to changes in the values it was previously bound to.
If needed, the property can still be updated again later through another assignment, but the automatic reactivity is lost.

This behavior also applies to most built-in `in-out` properties, such as the `text` property of a `TextInput`.
When the user interacts with the widget, for example by typing into the input,
this is considered an imperative assignment that will break any existing binding to that property.

To maintain reactivity in such cases, you can use a two-way binding (`<=>`),
or you can make use of the `changed` callback to track and respond to property updates.

## Performance

From a performance perspective, Slint works out what properties are changed. It then finds all the expressions
that depend on that value. These dependencies are then re-evaluated based on the new values and the UI will update.

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.



## Property Expressions

Expressions can vary in complexity:

```slint no-test
// Tracks the `x` value of an element called foo
x: foo.x;

// Tracks the value, but sets it to 0px or 400px based on if
// foo.x is greater than 400px
x: foo.x > 100px ? 0px : 400px;

// Tracks the value, but clamps it between 0px and 400px
x: clamp(foo.x, 0px, 400px);
```

As the last example shows functions can be used as part of a property expression. This can be
useful for when an expression is too complex to be readable or maintained as a single line.

```slint playground
export component MyComponent {
    width: 400px; height: 400px;

    pure function lengthToInt(n: length) -> int {
        return (n / 1px);
    }

    Rectangle {
        background: #151515;
    }

    ta := TouchArea {}

    myRect := Rectangle {
        x: ta.mouse-x;
        y: ta.mouse-y;
        width: 60px;
        height: 60px;
        background: ta.pressed ? orange : skyblue;
        Text {
            x: 5px; y: 5px;
            text: "x: " + lengthToInt(myRect.x);
            color: white;
        }
        Text {
            x: 5px; y: 20px;
            text: "y: " + lengthToInt(myRect.y);
            color: white;
        }
    }
}
```

Here the earlier example was updated to use a function to convert the length to an integer.
This also truncates the x and y values to be more readable i.e. '4' instead of '4.124488'.

## Purity

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(); }
}
```



## Two-Way Bindings

Create two-way bindings between properties with the `<=>` syntax. These properties will be linked
together and always contain the same value. Also known as bidirectional or bi-directional bindings.

The right hand side of the `<=>` must be a reference to a property of the same type,
or a field of the same type within a property of struct 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.

The initial value of a linked property will be the value of the right hand side of the binding.

```slint
struct Thing { name: string, price: int }

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;
    in-out property<Thing> thing;
    r:= Rectangle {
        background: blue;
    }
    input := TextInput {
        // The `thing.name` field will be sync'ed with the text when the user edits
        text <=> root.thing.name;
    }
}
```
