# Slider

> A styled native range input with a live percentage badge.

URL: https://apogee.avaui.dev/docs/slider
Last updated: 2026-10-15

A styled native range input with a live percentage badge.

Last updated October 15, 2026

Uses JavaScript

A small island updates the badge text and the track’s fill on every `input` event, keeps the badge centred over the thumb, and in `range` mode stops the two thumbs from crossing.

**Without JS:** The range input itself needs no JS — it's a native range input, fully draggable and keyboard-operable, and its initial coloured fill is rendered server-side from value/min/max. Only the floating value badge is JS-driven; it's hidden via no-js:hidden when scripts don't run.

```astro
<Slider aria-label="Volume" value={40} />
```

## Add

```sh
npx @ava-ui/apogee add slider
```

No Apogee component dependencies.

## Usage

```astro
---
import Slider from '@/components/apogee/Slider/Slider.astro'
---
<Slider name="volume" min={0} max={100} value={40} aria-label="Volume" />
```

## API

`@composable` — exposed to Content Editors in AVA. Any other `<input>` attribute (e.g. `id`, `aria-labelledby`, `data-*`) passes through onto the range input.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` | — | Form field name. |
| `min` | `number` | `0` | Minimum value. |
| `max` | `number` | `100` | Maximum value. |
| `step` | `number` | `1` | Step increment. |
| `value` | `number` | midpoint of `min`/`max` | Initial value. Clamped to `min`/`max` and snapped to `step` before render. |
| `disabled` | `boolean` | `false` | Disables the input. |
| `range` | `boolean` | `false` | Two thumbs. Uses `minValue` / `maxValue` and submits two fields. |
| `minValue` / `maxValue` | `number` | `min` / `max` | Initial thumb values in `range` mode. |
| `minName` / `maxName` | `string` | `<name>-min` / `<name>-max` | Submitted names in `range` mode. |
| `format` | `string \| false` | `'{value}'` | Badge text with a `{value}` token (`'${value}'`, `'{value}%'`). `false` hides the badge. |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Vertical turns the input; give the field a height with `class`. |
| `color` | `'primary' \| 'neutral' \| 'critical' \| 'positive' \| 'warning'` | `'primary'` | Hue of the filled track and thumb. |
| `labelPosition` | `'top' \| 'bottom'` | `'top'` | Where the badge sits relative to a horizontal track. |
| `aria-label` | `string` | — | Accessible name. No visible `<label>` is rendered — set this or associate an external `<label>` via `id` / `aria-labelledby`. |
| `class` | `string` | — | Extra classes on the wrapping `<div>`, merged last. |

## Value and format

The badge shows the value. `format` wraps it; `false` hides the badge.

```astro
<Slider min={0} max={50} value={10} format="${value}" aria-label="Budget" />
<Slider value={40} format="{value}%" aria-label="Opacity" />
<Slider value={25} format={false} aria-label="No badge" />
```

## Range

Two thumbs that never cross; submits `price-min` and `price-max`.

```astro
<Slider range name="price" min={0} max={100} step={10} minValue={20} maxValue={60} aria-label="Price" />
```

With a visible label, `aria-labelledby` names both thumbs; prefer `aria-label` when each thumb should be named on its own (“Budget minimum” / “Budget maximum”).

```astro
<label id="budget-label">Budget</label>
<Slider range name="budget" minValue={1000} maxValue={4000} max={5000} step={100} aria-labelledby="budget-label" />
```

## Orientation

```astro
<Slider aria-label="Volume" value={50} />
<Slider orientation="vertical" aria-label="Volume" class="h-48" />
```

## Variants

`labelPosition` — horizontal only:

```astro
<Slider aria-label="Top badge" labelPosition="top" value={30} />
<Slider aria-label="Bottom badge" labelPosition="bottom" value={70} />
```

Every `color`:

```astro
<Slider aria-label="Primary" color="primary" value={60} />
<Slider aria-label="Neutral" color="neutral" value={60} />
<Slider aria-label="Critical" color="critical" value={60} />
<Slider aria-label="Positive" color="positive" value={60} />
<Slider aria-label="Warning" color="warning" value={60} />
```

## States

-   **Default** — track fill matches `value` (or the midpoint if `value` is unset), rendered server-side so there’s no flash before JS loads.
-   **Hover** — pointer cursor over the track/thumb.
-   **Focus** — visible ring on the thumb (`focus-visible`).
-   **Disabled** — track and thumb take the disabled colour, `cursor-not-allowed`; native `disabled` blocks interaction and removes it from the tab order.
-   **No JS** — badge hidden (`no-js:hidden`); input and fill stay fully usable.

```astro
<Slider aria-label="Disabled" value={50} disabled />
```

## Examples

With a visible, associated label:

```astro
<label for="volume-slider">Volume</label>
<Slider id="volume-slider" name="volume" value={60} />
```

Controlled range with a fractional step:

```astro
<Slider name="rating" min={0} max={5} step={0.5} value={2.5} aria-label="Rating" />
```

## Accessibility

| Key | Action |
| --- | --- |
| `Tab` | Moves focus to the thumb; a range slider has one stop per thumb. |
| `←` `→` | Step down / up by `step`; swapped under `dir="rtl"`. |
| `↓` `↑` | Step down / up by `step`. |
| `PageDown` `PageUp` | Step down / up by a tenth of the range, or by `step` if that is larger. |
| `Home` `End` | Jump to `min` / `max`. |

-   No visible `<label>` is rendered — always pass `aria-label`, or associate an external `<label for>` with `id`.
-   The badge is `aria-hidden` — it echoes the input’s value visually; screen readers announce the native input’s value/min/max, not the badge text.
-   Visible focus ring on keyboard focus.
-   No JS: the badge disappears (`no-js:hidden`) but the slider stays fully operable — value, min, max, and the coloured fill are all rendered server-side.

## Tokens

| Token | Used for |
| --- | --- |
| `--background-{hue}` | Filled portion of the track, thumb fill (per `color`) |
| `--background-neutral` | Unfilled portion of the track |
| `--background-page` | Thumb border |
| `--border-neutral` | Thumb outer shadow ring |
| `--outline-color-focus` | Focus ring on the thumb |
| `--background-inverted` / `--on-inverted` | Badge |

## Do / Don’t

-   **Do** pair the slider with a visible value or unit nearby when precision matters — the badge is a nice-to-have echo, not a substitute for feedback.
-   **Do** set sensible `min`/`max`/`step` for the value being edited (percentages: 0–100 step 1; ratings: 0–5 step 0.5).
-   **Don’t** rely on the badge alone to communicate the value to screen reader users — it’s decorative.
-   **Don’t** omit `aria-label` (or an associated `<label>`) — without one the slider has no accessible name.

## Content

No visible label text is rendered by the component — write `aria-label` (or an external label) as a short noun phrase (“Volume”, “Price range”), not an instruction (“Drag to adjust volume”).

## Related

[

NumberInputA labeled numeric field with styled −/+ steppers, wired like Input.

](https://apogee.avaui.dev/docs/number-input)[

RatingA star rating on native radios — pick a value on a scale, or display one read-only.

](https://apogee.avaui.dev/docs/rating)[

ProgressA determinate or indeterminate progress bar.

](https://apogee.avaui.dev/docs/progress)
