# Slider

A number picked along a track, continuous or stepped, on either axis.

```slint
import { Slider } from "@glint/components/slider.slint";
import { Tokens } from "@glint/theme/tokens.slint";

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

    in-out property <float> volume: 65;

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

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;

                Slider {
                    minimum: 0;
                    maximum: 100;
                    value <=> root.volume;
                }
            }
        }

        Text {
            text: "Volume: " + Math.round(root.volume) + "%";
            color: Tokens.color-muted-foreground;
            font-size: Tokens.typography-body-sm-size;
            horizontal-alignment: center;
        }
    }
}
```

## Usage

```slint
import { Slider } from "@glint/components/slider.slint";

export component AppWindow inherits Window {
    in-out property <float> brightness: 80;

    VerticalLayout {
        alignment: center;

        Slider {
            minimum: 0;
            maximum: 100;
            step: 5;
            value <=> root.brightness;
            changed(val) => {
                // handle adjustment
            }
        }
    }
}
```

`Slider` enables users to select a single numeric value from a bounded range by dragging the thumb, clicking the track, or using arrow keys.

## Examples

### Orientations

The `orientation` property sets the slider axis:

- `SliderOrientation.horizontal`: Horizontal track filling left-to-right (default).
- `SliderOrientation.vertical`: Vertical track filling bottom-to-top (up increases value).

```slint
import { Slider, SliderOrientation } from "@glint/components/slider.slint";
import { Tokens } from "@glint/theme/tokens.slint";

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

    in-out property <float> horizontal-val: 40;
    in-out property <float> vertical-val: 75;

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

        HorizontalLayout {
            alignment: center;
            spacing: 48px;

            VerticalLayout {
                alignment: center;
                width: 240px;
                spacing: 12px;

                Slider {
                    orientation: SliderOrientation.horizontal;
                    value <=> root.horizontal-val;
                }

                Text {
                    text: "Horizontal: " + Math.round(root.horizontal-val);
                    color: Tokens.color-muted-foreground;
                    font-size: Tokens.typography-body-sm-size;
                    horizontal-alignment: center;
                }
            }

            VerticalLayout {
                alignment: center;
                spacing: 12px;

                Slider {
                    orientation: SliderOrientation.vertical;
                    value <=> root.vertical-val;
                }

                Text {
                    text: "Vertical: " + Math.round(root.vertical-val);
                    color: Tokens.color-muted-foreground;
                    font-size: Tokens.typography-body-sm-size;
                    horizontal-alignment: center;
                }
            }
        }
    }
}
```

### Discrete stepping

Set `step` to define snapping increments (such as `step: 25`). Setting `step: 0` enables smooth continuous sliding.

```slint
import { Slider } from "@glint/components/slider.slint";
import { Tokens } from "@glint/theme/tokens.slint";

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

    in-out property <float> step-val: 50;

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

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;

                Slider {
                    minimum: 0;
                    maximum: 100;
                    step: 25;
                    value <=> root.step-val;
                }
            }
        }

        Text {
            text: "Step value: " + Math.round(root.step-val);
            color: Tokens.color-muted-foreground;
            font-size: Tokens.typography-body-sm-size;
            horizontal-alignment: center;
        }
    }
}
```

### Disabled state

Setting `disabled: true` dims the track and thumb and blocks interactions.

```slint
import { Slider } from "@glint/components/slider.slint";
import { Tokens } from "@glint/theme/tokens.slint";

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

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 320px;

                Slider {
                    disabled: true;
                    value: 45;
                }
            }
        }
    }
}
```

## API Reference

### Properties

| Property        | Type                   | Default                        | Description                                                                                                                                                                                                                                                                                                                                                                                           |
| --------------- | ---------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `value`         | `in-out float`         | `0`                            | Two-way; current value snapped to `step` and clamped to `minimum..maximum` — see `step` for the one value that isn't.                                                                                                                                                                                                                                                                                 |
| `minimum`       | `in float`             | `0`                            | Lower bound (inclusive).                                                                                                                                                                                                                                                                                                                                                                              |
| `maximum`       | `in float`             | `100`                          | Upper bound (inclusive).                                                                                                                                                                                                                                                                                                                                                                              |
| `step`          | `in float`             | `1`                            | The grid every user-driven value lands on, counted from `minimum`: the pointer snaps to it exactly as the keyboard does, so a stepped slider cannot be dragged into a value its consumer never allowed. `0` turns snapping off — the continuous slider HTML spells `step="any"`. A value the \*consumer\* binds is left alone, off-grid or not, the way SpinBox leaves an out-of-range binding alone. |
| `disabled`      | `in bool`              | `false`                        | When true, the thumb dims and stops responding.                                                                                                                                                                                                                                                                                                                                                       |
| `orientation`   | `in SliderOrientation` | `SliderOrientation.horizontal` | Which way the slider runs. Horizontal fills left-to-right; vertical fills bottom-to-top, so up is more.                                                                                                                                                                                                                                                                                               |
| `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                                |
| ---------------- | ------------------------------------------ |
| `changed(float)` | Fired with the new `value` while dragging. |

### Functions

| Function                | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `increment()`           | Adds one `nudge`, bounded by `maximum` and landing on the grid.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `decrement()`           | Removes one `nudge`, bounded by `minimum` and landing on the grid.                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `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                   |
| ------------------- | ------------------------ |
| `SliderOrientation` | `horizontal`, `vertical` |

### SliderGrid

The value arithmetic both sliders share, in a global so [RangeSlider](/docs/components/range-slider) uses this one rather than re-deriving it. Both functions are pure and take the range they work in, so neither needs a component to live on — reach for them when you are computing a snapped value outside a slider.

### Functions

| Function                                                      | Description                                                                                                                                                                                                                                           |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `snapped(v: float, minimum: float, step: float) -> float`     | Rounds to the nearest point of the grid, counted from `minimum` so the grid starts where the range does. Always measured from `minimum` rather than accumulated, so a fractional step cannot drift over a long drag or a held key.                    |
| `nudge(minimum: float, maximum: float, step: float) -> float` | What one arrow key, or one accessible increment/decrement, moves by. That is `step` — except on a continuous slider, where the keyboard still has to move by \*something\*: a hundredth of the range, roughly the granularity the pointer has anyway. |

## Accessibility

- **Slider role.** Publishes `accessible-role: slider` with `accessible-value`, `accessible-value-minimum`, and `accessible-value-maximum`.
- **Keyboard navigation.** `←`/`↓` decreases value, `→`/`↑` increases value, `Home` jumps to minimum, and `End` jumps to maximum.
- **Focus ring.** Displays a 2px outer focus ring when keyboard focus is active.
