Skip to content

Slint Python API

Slint ↗ is a UI toolkit that supports different programming languages. Slint-python is the integration with Python.

This documentation describes slint 1.19.0b1.

Install Slint with uv or pip from the Python Package Index ↗:

Terminal window
uv add slint
bash

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 ↗.

  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:
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();
}
}
}
}
slint
  1. Create a file called main.py:
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()
python
  1. Run it with uv run main.py.

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

  1. Call load_file. The returned object is a namespace ↗ that provides every exported component that inherits Window:

    import slint
    components = slint.load_file("app.slint")
    main_window = components.MainWindow()
    python
  2. Use Slint’s auto-loader, which lazily loads .slint files from sys.path:

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

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 callback decorator when sub-classing:

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

Set array properties from Python by passing subclasses of Model. Use ListModel to construct a model from an iterable:

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

Use MapModel to show the rows of another model through a map function. It follows the changes of the source model:

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

Alternatively, subclass MapModel and implement map_row() instead of passing a function.

Use 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 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 SortModel to show the rows of another model in sorted order. Like sorted(), it takes an optional key function and a reverse flag:

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

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 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.

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))
python

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():

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()
python

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

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

.slint typePython type
intint
floatfloat
boolbool
stringstr
colorColor
brushBrush
imageImage
styled-textStyledText
data-transferDataTransfer
length, physical-length, duration, angle, relative-font-sizefloat
structuredict / Struct
arrayModel
PointLogicalPosition

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


© 2026 SixtyFPS GmbH