# Toggle

A button that stays pressed — a tool state rather than an action.

```slint
import { Toggle } from "@glint/components/toggle.slint";
import { Icon } from "@glint/components/icon.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;

    in-out property <bool> is-pinned: false;

    VerticalLayout {
        alignment: center;
        spacing: 16px;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            Toggle {
                text: "Pin to Top";
                pressed <=> root.is-pinned;

                Icon {
                    icon: IconSet.Pin;
                    size: 16px;
                }
            }
        }

        Text {
            text: root.is-pinned ? "Item is pinned" : "Item is unpinned";
            color: Tokens.color-muted-foreground;
            font-size: Tokens.typography-body-sm-size;
            horizontal-alignment: center;
        }
    }
}
```

## Usage

```slint
import { Toggle } from "@glint/components/toggle.slint";
import { Icon } from "@glint/components/icon.slint";
import { IconSet } from "@lucide";

export component AppWindow inherits Window {
    in-out property <bool> bookmark: false;

    VerticalLayout {
        alignment: center;

        Toggle {
            text: "Bookmark";
            pressed <=> root.bookmark;
            toggled(is-pressed) => {
                // handle state change
            }

            Icon {
                icon: IconSet.Bookmark;
                size: 16px;
            }
        }
    }
}
```

`Toggle` renders a two-state button that stays pressed when active. It supports text labels, slotted icons, multiple visual variants, and density presets.

## Examples

### Variants

`variant` configures the background and border appearance:

- `ToggleVariant.default`: Clean background that fills with accent color when pressed.
- `ToggleVariant.outline`: Hairline border with subtle surface hover styling.

```slint
import { Toggle, ToggleVariant } from "@glint/components/toggle.slint";
import { Icon } from "@glint/components/icon.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;
        spacing: 16px;
        padding: 24px;

        HorizontalLayout {
            alignment: center;
            spacing: 16px;

            Toggle {
                variant: ToggleVariant.default;
                text: "Default";
                pressed: true;

                Icon { icon: IconSet.Star; size: 16px; }
            }

            Toggle {
                variant: ToggleVariant.outline;
                text: "Outline";
                pressed: false;

                Icon { icon: IconSet.Star; size: 16px; }
            }
        }
    }
}
```

### Sizes

`size` controls button height, internal padding, and font size:

- `ToggleSize.sm`: Compact height (`28px`).
- `ToggleSize.default`: Standard height (`36px`).
- `ToggleSize.lg`: Larger touch target (`40px`).

```slint
import { Toggle, ToggleSize } from "@glint/components/toggle.slint";
import { Icon } from "@glint/components/icon.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;
        spacing: 16px;
        padding: 24px;

        HorizontalLayout {
            alignment: center;
            spacing: 16px;

            Toggle {
                size: ToggleSize.sm;
                text: "Small";
                Icon { icon: IconSet.Bold; size: 14px; }
            }

            Toggle {
                size: ToggleSize.default;
                text: "Default";
                pressed: true;
                Icon { icon: IconSet.Bold; size: 16px; }
            }

            Toggle {
                size: ToggleSize.lg;
                text: "Large";
                Icon { icon: IconSet.Bold; size: 18px; }
            }
        }
    }
}
```

### Icon-only toggles

When `text` is omitted, `Toggle` automatically adopts a square aspect ratio matching its height.

```slint
import { Toggle } from "@glint/components/toggle.slint";
import { Icon } from "@glint/components/icon.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: 8px;

            Toggle {
                pressed: true;
                Icon { icon: IconSet.Bold; size: 16px; }
            }

            Toggle {
                Icon { icon: IconSet.Italic; size: 16px; }
            }

            Toggle {
                Icon { icon: IconSet.Underline; size: 16px; }
            }
        }
    }
}
```

## API Reference

### Properties

| Property        | Type               | Default                 | Description                                                                                                                                                                                                                                                                              |
| --------------- | ------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`          | `in string`        | no default              | Label rendered inside.                                                                                                                                                                                                                                                                   |
| `size`          | `in ToggleSize`    | `ToggleSize.default`    | Height + horizontal padding preset — sm, default, lg.                                                                                                                                                                                                                                    |
| `pressed`       | `in-out bool`      | `false`                 | Two-way pressed state.                                                                                                                                                                                                                                                                   |
| `variant`       | `in ToggleVariant` | `ToggleVariant.default` | Visual style — `default` or `outline`.                                                                                                                                                                                                                                                   |
| `disabled`      | `in bool`          | `false`                 | When true, dims and stops responding.                                                                                                                                                                                                                                                    |
| `focus-visible` | `out bool`         | no default              | Whether this control holds the keyboard \*and\* got it from the keyboard — the `focus-visible` a hover surface opens on. Published because Slint reports focus only to the element holding it, so a `Tooltip` wrapping this control cannot read it off the scope inside (tooltip.slint). |
| `focus-held`    | `out bool`         | no default              | The same focus, still true while a popup has borrowed the window's — what a hover surface opened by this control has to gate on, since showing itself is what takes `focus-visible` away. See `Tooltip`.                                                                                 |

### Callbacks

| Callback        | Description                         |
| --------------- | ----------------------------------- |
| `toggled(bool)` | Fired with the new `pressed` value. |

### Functions

| Function                | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `focus-from-keyboard()` | Hand the control the keyboard the way a key press does, ring and all. A host that moves the focus onto a control because the user pressed something — `Questionnaire` stepping to the next question — cannot use `focus()`: Slint reports that as `programmatic`, which is how a host parking the keyboard looks, and the scope drops the ring for it. Published by every control that publishes `focus-visible`, for the same reason: the scope inside cannot be reached from outside the component. |

### Enums

| Enum            | Values                |
| --------------- | --------------------- |
| `ToggleSize`    | `sm`, `default`, `lg` |
| `ToggleVariant` | `default`, `outline`  |

## Accessibility

- **Checkbox role.** Publishes `accessible-role: checkbox` with `accessible-checkable: true` and `accessible-checked: root.pressed`.
- **Keyboard navigation.** `Space` or `Enter` flips the pressed state.
- **Focus ring.** Displays a focus ring when active via keyboard navigation.
