---
title: "Slint Python API"
description: "Build fluid graphical user interfaces in Python with Slint."
---
import XRef from "../../components/XRef.astro";
import SlintRef from "../../components/SlintRef.astro";
import pkg from "../../version.json";

[Slint](https://slint.dev/) is a UI toolkit that supports different programming
languages. Slint-python is the integration with Python.

This documentation describes `slint` {pkg.version}.

:::caution[Beta]
Slint-python is in a beta phase of development: the APIs, while mostly stable,
may be subject to further changes. Any changes are documented in the
[ChangeLog](https://github.com/slint-ui/slint/blob/master/CHANGELOG.md). You can
track the progress of the Python integration via the
[python-labelled issues](https://github.com/slint-ui/slint/labels/a%3Alanguage-python).
:::

## Prerequisites

- [Python 3.12 or newer](https://python.org/)
- [uv](https://docs.astral.sh/uv/) or [pip](https://pypi.org/project/pip/)

## Installation

Install Slint with `uv` or `pip` from the [Python Package Index](https://pypi.org):

```bash
uv add slint
```

The installation uses binaries provided for macOS, Windows, and Linux for
various architectures. If your target platform is not covered by binaries, `uv`
will automatically build Slint from source. If that happens, you will need some
software development tools on your machine, as well as
[Rust](https://www.rust-lang.org/learn/get-started).

## Quick start

1. Create a new project with `uv init`.
2. Add the Slint Python package to your project: `uv add slint`.
3. Create a file called `app-window.slint`:

```slint
import { Button, VerticalBox } from "std-widgets.slint";

export component AppWindow inherits Window {
    in-out property<int> counter: 42;
    callback request-increase-value();
    VerticalBox {
        Text {
            text: "Counter: \{root.counter}";
        }
        Button {
            text: "Increase value";
            clicked => {
                root.request-increase-value();
            }
        }
    }
}
```

4. Create a file called `main.py`:

```python
import slint

# slint.loader will look in `sys.path` for `app-window.slint`.
class App(slint.loader.app_window.AppWindow):
    @slint.callback
    def request_increase_value(self):
        self.counter = self.counter + 1

app = App()
app.run()
```

5. Run it with `uv run main.py`.

## Instantiating a component

Exported components are exposed as Python classes. To access such a class, you
have two options:

1. Call <XRef to="load_file" />. The returned object is a
   [namespace](https://docs.python.org/3/library/types.html#types.SimpleNamespace)
   that provides every exported component that inherits <SlintRef type="Window" />:

   ```python
   import slint
   components = slint.load_file("app.slint")
   main_window = components.MainWindow()
   ```

2. Use Slint's auto-loader, which lazily loads `.slint` files from `sys.path`:

   ```python
   import slint
   main_window = slint.loader.app.MainWindow()
   ```

## Callbacks

Callbacks declared in `.slint` files are visible as callable properties on the
component instance. Assign a Python callable to set a handler, or use the
<XRef to="callback" /> decorator when sub-classing:

```python
import slint

class Component(slint.loader.my_component.MyComponent):
    @slint.callback
    def clicked(self):
        print("hello")

component = Component()
```

## Arrays and models

Set array properties from Python by passing subclasses of <XRef to="Model" />.
Use <XRef to="ListModel" /> to construct a model from an iterable:

```python
component.model = slint.ListModel([1, 2, 3])
component.model.append(4)
del component.model[0]
```

Use <XRef to="MapModel" /> to show the rows of another model through a map function.
It follows the changes of the source model:

```python
numbers = slint.ListModel([1, 2, 3])
component.labels = slint.MapModel(numbers, lambda n: f"Item {n}")
numbers.append(4)
```

Alternatively, subclass <XRef to="MapModel" /> and implement `map_row()` instead of passing a function.

Use <XRef to="ReverseModel" /> to show the rows of another model in reverse order.
Setting one of its rows sets the corresponding row of the source model.

Use <XRef to="FilterModel" /> to show only the rows of another model for which a filter function returns true.
Alternatively, subclass it and implement `filter_row()`, and call `reset()` when the filter's result changes.

Use <XRef to="SortModel" /> to show the rows of another model in sorted order.
Like `sorted()`, it takes an optional `key` function and a `reverse` flag:

```python
component.names = slint.SortModel(people, key=lambda person: person.name)
```

## Threading

The event loop runs on the main thread, and components must be created and
accessed from that same thread.
Doing blocking work there stalls rendering and input, so move it to another
thread and apply the result back on the main thread.

Pass a coroutine to <XRef to="run_event_loop" /> to run `asyncio` alongside the
Slint event loop.
Use `asyncio.to_thread()` for blocking work: it runs the function on a worker
thread, and the code after the `await` continues on the main thread, where it is
safe to update a model.

```python
import asyncio
import slint

def enumerate_devices() -> list[str]:
    # Runs on a worker thread, so it may block.
    return scan_usb_bus()

async def main(component: slint.Component) -> None:
    names = await asyncio.to_thread(enumerate_devices)
    # Back on the main thread: safe to touch the model.
    for name in names:
        component.devices.append(name)

component.devices = slint.ListModel([])
slint.run_event_loop(main(component))
```

When the work happens on a thread you don't drive yourself, such as a device
callback or a `threading.Thread`, hand the update back with
`loop.call_soon_threadsafe()`:

```python
import asyncio
import slint
import threading

def worker(loop: asyncio.AbstractEventLoop, model: slint.ListModel) -> None:
    for name in scan_usb_bus():
        loop.call_soon_threadsafe(model.append, name)

async def main(model: slint.ListModel) -> None:
    loop = asyncio.get_running_loop()
    threading.Thread(target=worker, args=(loop, model), daemon=True).start()
```

Calling a model method directly from another thread is not supported.

## Type mappings

Each type used for properties in the Slint language translates to a specific
Python type:

| `.slint` type | Python type |
| --- | --- |
| <SlintRef type="int" /> | `int` |
| <SlintRef type="float" /> | `float` |
| <SlintRef type="bool" /> | `bool` |
| <SlintRef type="string" /> | `str` |
| <SlintRef type="color" /> | <XRef to="Color" /> |
| <SlintRef type="brush" /> | <XRef to="Brush" /> |
| <SlintRef type="image" /> | <XRef to="Image" /> |
| <SlintRef type="styled-text" /> | <XRef to="StyledText" /> |
| <SlintRef type="data-transfer" /> | <XRef to="DataTransfer" /> |
| `length`, `physical-length`, `duration`, `angle`, `relative-font-size` | `float` |
| structure | `dict` / `Struct` |
| array | <XRef to="Model" /> |
| <SlintRef type="Point" /> | <XRef to="LogicalPosition" /> |

For the full set of classes and module-level functions, see the **API**
section in the sidebar.