# Empty

The pane that stands where content would be — nothing found, nothing yet, nothing set up.

```slint
import { Empty, EmptyMedia, EmptyMediaVariant, EmptyTitle, EmptyDescription, EmptyContent } from "@glint/components/empty.slint";
import { Button, ButtonVariant } from "@glint/components/button.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            Empty {
                EmptyMedia {
                    icon: IconSet.FolderPlus;
                    variant: EmptyMediaVariant.framed;
                }

                EmptyTitle {
                    text: "No projects created";
                }

                EmptyDescription {
                    text: "Get started by creating your first workspace project.";
                }

                EmptyContent {
                    Button {
                        text: "New Project";
                    }

                    Button {
                        text: "Import";
                        variant: ButtonVariant.outline;
                    }
                }
            }
        }
    }
}
```

## Usage

```slint
import { Empty, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent } from "@glint/components/empty.slint";
import { Button } from "@glint/components/button.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component AppWindow inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        Empty {
            EmptyMedia {
                icon: IconSet.Inbox;
            }

            EmptyTitle {
                text: "No new notifications";
            }

            EmptyDescription {
                text: "You are all caught up for the day.";
            }
        }
    }
}
```

`Empty` provides a standard zero-state layout. It establishes balanced spacing between media icons, titles, descriptions, and action buttons.

## Examples

### Media variants

Use `variant: EmptyMediaVariant.framed` to wrap the icon in a rounded, bordered card, or `variant: EmptyMediaVariant.bare` for a simple unbordered icon.

```slint
import { Empty, EmptyMedia, EmptyMediaVariant, EmptyTitle, EmptyDescription } from "@glint/components/empty.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;
            spacing: 32px;

            Empty {
                EmptyMedia {
                    icon: IconSet.Search;
                    variant: EmptyMediaVariant.bare;
                }

                EmptyTitle {
                    text: "Bare media";
                }

                EmptyDescription {
                    text: "Unbordered glyph style.";
                }
            }

            Empty {
                EmptyMedia {
                    icon: IconSet.Search;
                    variant: EmptyMediaVariant.framed;
                }

                EmptyTitle {
                    text: "Framed media";
                }

                EmptyDescription {
                    text: "Bordered container style.";
                }
            }
        }
    }
}
```

### Title and description type

`EmptyTitle` is a [Heading](/docs/components/typography) and `EmptyDescription` is a `Body`, so the empty state is tuned with the type ladder’s own knobs rather than with styles of its own: `tone` picks the color role, `level` steps the heading and `size` steps the description.

```slint
import { Empty, EmptyDescription, EmptyMedia, EmptyTitle } from "@glint/components/empty.slint";
import { BodySize, TypographyTone } from "@glint/components/typography.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        Empty {
            EmptyMedia { icon: IconSet.TriangleAlert; }

            EmptyTitle {
                text: "Sync stopped";
                level: 3;
                tone: TypographyTone.danger;
            }

            EmptyDescription {
                text: "The last three runs failed to reach the server.";
                size: BodySize.sm;
                tone: TypographyTone.muted;
            }
        }
    }
}
```

## API Reference

`Empty` publishes no properties, callbacks or functions of its own. What a call site can set on it is the Slint `Rectangle` it inherits.

### EmptyMedia

What stands for the missing thing, at the top of the pane: a glyph, a spinner while the answer is still coming, an avatar for “nobody is here”, an image. `icon` is the common case; anything else goes in the `@children` slot, and `variant` decides whether it is framed.

### Properties

| Property  | Type                   | Default                  | Description                                                                                  |
| --------- | ---------------------- | ------------------------ | -------------------------------------------------------------------------------------------- |
| `variant` | `in EmptyMediaVariant` | `EmptyMediaVariant.bare` | `bare` (default) draws the media as it is; `framed` wraps it in a bordered, muted container. |
| `icon`    | `in LucideIcon`        | no default               | Glyph shorthand, normally selected from `IconSet` in lucide-slint.                           |

### Enums

| Enum                | Values           |
| ------------------- | ---------------- |
| `EmptyMediaVariant` | `bare`, `framed` |

### EmptyTitle

The heading of the empty state. `level` is a step on the type ladder rather than an outline level — see [Typography](/docs/components/typography#usage).

### Properties

| Property | Type                | Default                  | Description                                                                                                           |
| -------- | ------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `level`  | `in int`            | `1`                      | Which step, 1 (largest) through 5 (smallest). Out-of-range levels take the smallest step rather than drawing nothing. |
| `tone`   | `in TypographyTone` | `TypographyTone.default` | Colour role — `default`, `muted`, `subtle`.                                                                           |

### Enums

| Enum             | Values                                           |
| ---------------- | ------------------------------------------------ |
| `TypographyTone` | `default`, `muted`, `subtle`, `accent`, `danger` |

### EmptyDescription

The line under the heading, saying what to do about it.

### Properties

| Property | Type                | Default                  | Description                                             |
| -------- | ------------------- | ------------------------ | ------------------------------------------------------- |
| `size`   | `in BodySize`       | `BodySize.default`       | Which step — `lg`, `default`, `sm`, `label`, `caption`. |
| `tone`   | `in TypographyTone` | `TypographyTone.default` | Colour role — `default`, `muted`, `subtle`.             |

### Enums

| Enum             | Values                                           |
| ---------------- | ------------------------------------------------ |
| `BodySize`       | `lg`, `default`, `sm`, `label`, `caption`        |
| `TypographyTone` | `default`, `muted`, `subtle`, `accent`, `danger` |

### EmptyContent

The controls a zero state offers, in a row under the text.

`EmptyContent` publishes no properties, callbacks or functions of its own. What a call site can set on it is the Slint `HorizontalLayout` it inherits.

## Accessibility

- **`EmptyTitle` is a size, not an outline level.** Its `level: 5` picks a step on the type ladder ([Typography](/docs/components/typography#usage)): `Heading` inherits Slint’s `Text` and declares no `accessible-role`, so nothing here opens a heading node or a landmark. The title is announced as text, in the order it is laid out.
- **Name the pane if a reader has to find it.** An empty state that replaces a region — a results list, a panel — is worth naming where that region is, with `accessible-role: region` and `accessible-label` set together at the call site; Slint refuses either without the other. `Empty` ships neither, because only the host knows what the pane stands in for.
- **The actions are the accessible part.** Buttons inside `EmptyContent` keep their own role, name, focus ring and default action, and are reached with `Tab` like any other control. Nothing in `Empty` takes focus, so a zero state with no action is a stop the keyboard passes straight over.
