---
// cSpell: ignore otherlib
title: The `.slint` File
description:  The `.slint` File
---

import CodeSnippetMD from '@slint/common-files/src/components/CodeSnippetMD.astro';
import Link from '@slint/common-files/src/components/Link.astro';
import LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';
import { Tabs, TabItem } from '@astrojs/starlight/components';


You write user interfaces in the Slint language and saved in files with the `.slint` extension.

Each `.slint` file defines one or several components. These components declare
a tree of elements. Components form the basis of composition in Slint. Use them
to build your own re-usable set of UI controls. You can use each declared
component under its name as an element in another component.

Below is an example of components and elements:

```slint

component MyButton inherits Text {
    color: black;
    // ...
}

export component MyApp inherits Window {
    preferred-width: 200px;
    preferred-height: 100px;
    Rectangle {
        width: 200px;
        height: 100px;
        background: green;
    }
    MyButton {
        x:0;y:0;
        text: "hello";
    }
    MyButton {
        y:0;
        x: 50px;
        text: "world";
    }
}
```

Both `MyButton` and `MyApp` are components. `Window` and `Rectangle` are built-in elements
used by `MyApp`. `MyApp` also re-uses the `MyButton` component as two separate elements.

Elements have properties, which you can assign values to. The example above assigns a string
constant "hello" to the first `MyButton`'s `text` property. You
can also assign entire expressions. Slint re-evaluates the expressions when any
of the properties they depend on change, which makes the user-interface reactive.

You can name elements using the `:=` syntax:

```slint
component MyButton inherits Text {
    // ...
}

export component MyApp inherits Window {
    preferred-width: 200px;
    preferred-height: 100px;

    hello := MyButton {
        x:0;y:0;
        text: "hello";
    }
    world := MyButton {
        y:0;
        text: "world";
        x: 50px;
    }
}
```

:::note{Note}
Names have to be valid [identifiers](#identifiers).
:::

Some elements are also accessible under pre-defined names:

-   `root` refers to the outermost element of a component.
-   `self` refers to the current element.
-   `parent` refers to the parent element of the current element.

These names are reserved and you can't re-define them.


## Comments

Comments are lines of code that are ignored by the Slint compiler. They are used to explain the code or
to temporarily disable code.

### Single Line Comments

Single line comments are denoted by `//` and are terminated by a new line.

```slint
// Amazing text! This is a comment
```

### Multi Line Comments

Multi line comments are denoted by `/*` and `*/` and are terminated by a new line.

```slint
/*
    This is a multi line comment.
    It can span multiple lines.
*/
```


## Elements and Components

The core part of the Slint language are elements and components. Technically they are the same thing
so once you know how to declare and use one you know the other. Elements are the basic building blocks
that are part of the Slint Language, while components (also know as widgets) are larger items that
are built up from multiple elements and properties.

If you have come from other languages such as HTML or React you might be used to opening and closing tags as well
as self closing tags.

```html
<!-- opening and closing tag -->
<Button>Hello World</Button>
 <!-- self closing tag -->
<img/>
```

Slint simply has a single way to declare an item the `element-name` followed by a set of curly braces `{}` that contain
the properties of the element.

```slint no-test del="Text {};"
// valid
Text {}

Text {
}
// Valid, but considered bad Slint practice
Text
{
}

// Not valid due to terminating semicolon
Text {};
```

:::note[Note]
The Slint tooling provides a code formatter that enforces what is considered good practice.

If you are new to coding then you can make friends with fellow developers by discussing aspects of
code formatting you don't like. It's a type of small talk developers love and appreciate.
:::




## The Root Element


```slint playground
component MyApp {
    Text {
        text: "Hello World";
        font-size: 24px;
    }
}
```

To be a valid Slint file the root element must be a component. Then inside the component you can declare
any number of elements. This is explained in more detail later, it's not important to understand at this point.

## Properties

Properties are the values that are assigned to an element. They are set using the `property-name: value;` syntax.


## Identifiers

Identifiers can be composed of letter (`a-zA-Z`), of numbers (`0-9`), or of the underscore (`_`) or the dash (`-`).
They can't start with a number or a dash (but they can start with underscore)
The underscores are normalized to dashes. Which means that these two identifiers are the same: `foo_bar` and `foo-bar`.

## Conditional Elements

The `if` construct instantiates an element only if a given condition is true.
The syntax is `if condition : id := Element { ... }`

```slint playground
export component Example inherits Window {
    preferred-width: 50px;
    preferred-height: 50px;
    if area.pressed : foo := Rectangle { background: blue; }
    if !area.pressed : Rectangle { background: red; }
    area := TouchArea {}
}
```


## Modules
Components declared in a `.slint` file can be used as elements in other
`.slint` files, by means of exporting and importing them.

By default, every type declared in a `.slint` file is private. The `export`
keyword changes this.

```slint
component ButtonHelper inherits Rectangle {
    // ...
}

component Button inherits Rectangle {
    // ...
    ButtonHelper {
        // ...
    }
}

export { Button }
```

In the above example, `Button` is accessible from other `.slint` files, but
`ButtonHelper` isn't.

It's also possible to change the name just for the purpose of exporting, without
affecting its internal use:

```slint
component Button inherits Rectangle {
    // ...
}

export { Button as ColorButton }
```

In the above example, `Button` isn't accessible from the outside, but
is available under the name `ColorButton` instead.

For convenience, a third way of exporting a component is to declare it exported
right away:

```slint
export component Button inherits Rectangle {
    // ...
}
```

Similarly, components exported from other files may be imported:

```slint no-test
import { Button } from "./button.slint";

export component App inherits Rectangle {
    // ...
    Button {
        // ...
    }
}
```

In the event that two files export a type under the same name, then you have the option
of assigning a different name at import time:

```slint no-test
import { Button } from "./button.slint";
import { Button as CoolButton } from "../other_theme/button.slint";

export component App inherits Rectangle {
    // ...
    CoolButton {} // from other_theme/button.slint
    Button {} // from button.slint
}
```

Elements, globals and structs can be exported and imported.

It's also possible to export globals (see <Link type="Globals" label="Global Singletons" />) imported from
other files:

```slint no-test
import { Logic as MathLogic } from "math.slint";
export { MathLogic } // known as "MathLogic" when using native APIs to access globals
```

## Module Syntax

The following syntax is supported for importing types:

```slint no-test
import { MyButton } from "module.slint";
import { MyButton, MySwitch } from "module.slint";
import { MyButton as OtherButton } from "module.slint";
import {
    MyButton,
    /* ... */,
    MySwitch as OtherSwitch,
} from "module.slint";
```

The following syntax is supported for exporting types:

```slint no-test
// Export declarations
export component MyButton inherits Rectangle { /* ... */ }

// Export lists
component MySwitch inherits Rectangle { /* ... */ }
export { MySwitch }
export { MySwitch as Alias1, MyButton as Alias2 }

// Re-export types from other module
export { MyCheckBox, MyButton as OtherButton } from "other_module.slint";

// Re-export all types from other module (only possible once per file)
export * from "other_module.slint";
```

## Component Libraries

Splitting your code base into separate module files promotes re-use and
improves encapsulation by allow you to hide helper components. This works
well within a project's own directory structure. To share libraries of
components between projects without hardcoding their relative paths, use
the component library syntax:

```slint no-test
import { MySwitch } from "@mylibrary/switch.slint";
import { MyButton } from "@otherlibrary";
```

In the above example, the `MySwitch` component will be imported from a component
library called `mylibrary`, in which Slint looks for the `switch.slint` file. Therefore `mylibrary` must be
declared to refer to a directory, so that the subsequent search for `switch.slint`
succeeds. `MyButton` will be imported from `otherlibrary`. Therefore `otherlibrary`
must be declared to refer to a `.slint` file that exports `MyButton`.

The path to each library, as file or directory, must be defined separately at compilation time.
Use one of the following methods to help the Slint compiler resolve libraries to the correct
path on disk:

<Tabs syncKey="dev-language">
<TabItem label="C++">
* Specify `LIBRARY_PATHS` with <LangRefLink lang="cpp" relpath="cmake_reference#slint-target-sources">`slint_target_sources`</LangRefLink>. For example:

```cmake
slint_target_sources(my_application
    ui/main.slint
    LIBRARY_PATHS
        material=${CMAKE_CURRENT_SOURCE_DIR}/material-1.0/material.slint
)
```

</TabItem>
<TabItem label="Rust">
* In `build.rs`, call <LangRefLink lang="rust-slint-build" relpath="struct.CompilerConfiguration#method.with_library_paths">`with_library_paths`</LangRefLink>
  to provide a mapping from library name to path. For example:

```rust
// build.rs
fn main() {
    let manifest_dir = std::path::PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap());
    let library_paths = std::collections::HashMap::from([(
        "example".to_string(),
        manifest_dir.join("third_party/example/ui/lib.slint"),
    )]);
    let config = slint_build::CompilerConfiguration::new().with_library_paths(library_paths);
    slint_build::compile_with_config("ui/main.slint", config).unwrap();
}
```

</TabItem>
<TabItem label="NodeJS">
* Provide the `libraryPaths` map with <LangRefLink lang="nodejs" relpath="functions/loadFile">`loadFile`</LangRefLink> in `LoadFileOptions`. For example:

```javascript
let ui = slint.loadFile("/path/to/main.slint", {
    libraryPaths: {
        "material": "/path/to/material-1.0/material.slint"
    }
});
```

</TabItem>
<TabItem label="Python">
* Provide the `library_paths` dict with <LangRefLink lang="python" relpath="slint#load_file">`load_file`</LangRefLink>. For example:

```python
ui = slint.load_file(
    "/path/to/main.slint",
    library_paths={
        "material": "/path/to/material-1.0/material.slint"
    },
)
```

</TabItem>
</Tabs>


* When invoking the `slint-viewer` from the command line, pass `-Lmylibrary=/path/to/my/library` for each component
  library.
* When using the VS Code extension, configure the Slint extension's library path
  using the `Slint: Library Paths` setting. Example below:
  ```json
  "slint.libraryPaths": {
      "mylibrary": "/path/to/my/library",
      "otherlibrary": "/path/to/otherlib/index.slint",
  },
  ```
  This can also be edited in the `.vscode/settings.json` file committed to your repository.
  Relative paths are resolved against the workspace root.
* With other editors, you can configure them to pass the `-L` argument to the `slint-lsp` just like for the slint-viewer.
