Skip to main content

Slider

Info:Controls html svelte astro Success: coverage 50/50

A draggable range control for choosing a single value between a min and max, with full keyboard support.

Live demo

live · @xoji/astro

Slider

A settings panel

Volume Brightness Locked

Value readout

Volume Opacity

Sizes

Small Medium Large

Every tone

Accents

accent accent-2 accent-3 accent-4 neutral

Statuses

success info warn danger

Named hues

red orange yellow green blue purple brown pink cyan gray white black

Slider picks one number across a range. It renders a rail with a fill showing the chosen portion and a role="slider" thumb carrying aria-valuemin/aria-valuemax/aria-valuenow, so pointer drag, click-to-position, and the full arrow/Page/Home/End keyboard set all move it.

Values snap to step and clamp to [min, max]. It is form-associated: give it a name and it contributes its current value to form data. Three sizes (sm, the default md, and lg) vary the thumb and rail thickness. It is the primitive the hue and alpha tracks of a color picker compose from.

When to use

How this component composes with the rest of the set.

Pair with Field or a form to capture the value; give it a name so it contributes to submitted data.
Use a tight step for coarse adjustments (a 0–10 rating) or step="1" over a wide range for fine ones.
It is the building block for a color picker's hue and alpha tracks: same rail, fill, and thumb mechanics with a gradient rail.

Props

13 props, straight from the manifest.

PropTypeDefaultBindingsDescription
value number min
html svelte astro
The current value, snapped to `step` and clamped to `[min, max]`. Two-way bindable in Svelte; reflected to `aria-valuenow`.
min number 0
html svelte astro
The lower bound of the range.
max number 100
html svelte astro
The upper bound of the range.
step number 1
html svelte astro
The granularity values snap to; arrow keys move by one step, Page keys by ten.
disabled boolean false
html svelte astro
Disables interaction; mutes the fill and thumb, drops the thumb out of the tab order, and sets `aria-disabled`.
size Size
sm md lg
md
html svelte astro
Control size (`sm`, `md`, or `lg`) varying the thumb and rail thickness.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
accent
html svelte astro
Color of the rail fill and thumb. Any of the semantic roles, accent variants, or named hues.
label string
html svelte astro
Visible label, also wired as the accessible name via `aria-labelledby`.
labelledby string
html svelte astro
ID of an external element that names the slider. Takes precedence over `label`.
name string
html svelte astro
Form field name; the slider contributes its current value to submitted form data.
show-value boolean false
html svelte astro
Renders the current value inline beside the label. The readout is `aria-hidden` since the thumb's `aria-valuenow` already announces it. Format it with the `format` property.
hide-label boolean false
html svelte astro
Visually hides the `label` text while still using it to name the control for assistive tech. Use it when the host already renders its own visible label but the slider still needs an accessible name.
format (value: number) => string
html svelte
A JS property (not an attribute) on the element: a function that formats the `show-value` readout. Defaults to the raw number. Settable in the HTML binding and via `bind:format` in Svelte; not available in the static Astro binding.

Appearance

Sizes

sm

.xoji-slider--sm

Compact: thin rail, small thumb.

md

default
.xoji-slider

Default.

lg

.xoji-slider--lg

Large: thicker rail, bigger thumb for touch.

States

hover

.xoji-slider__thumb:hover::after

Pointer over the thumb. Overlay paints the hover tint.

active

.xoji-slider__thumb:active::after

Thumb pressed or dragging. Overlay paints the press tint.

focus-visible

.xoji-slider__thumb:focus-visible

Keyboard focus on the thumb: a token-colored ring, plus a transparent outline that becomes real in forced-colors mode.

disabled

.xoji-slider--disabled

Non-interactive: muted fill and thumb, thumb removed from the tab order.

Anatomy

The named parts that make up the component, with their selectors.

slider

.xoji-slider

The column wrapper carrying the size and disabled classes and stacking the optional label above the rail.

--font-sans --text-body --leading-tight --fg-0 --space-2

rail

.xoji-slider__rail

The interactive track the thumb travels along; its ::before paints the unfilled groove.

--space-5 --space-2 --radius-full --neutral-bg --border-thin --line-2

fill

.xoji-slider__fill

The accent-colored portion of the rail from the minimum to the current value.

--accent --radius-full

thumb

.xoji-slider__thumb

The draggable role="slider" knob positioned at the current value.

--space-5 --radius-full --bg-0 --border-normal --accent --elevation-1

header

.xoji-slider__header

The row above the rail that lays out the label and value readout on opposite ends when either is shown.

--space-2

label

.xoji-slider__label

The optional visible label that names the slider and is referenced as its accessible name.

--fg-1 --text-sm

value

.xoji-slider__value

The optional inline readout of the current value, shown when show-value is set and formatted by the format property.

--fg-1 --text-sm

overlay

.xoji-slider__thumb::after

The pseudo-element on the thumb that paints hover and active state tints.

--state-hover --state-press

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 50/50 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --accent-2 --accent-3 --accent-4 --bg-0 --black --blue --border-normal --border-thick --border-thin --brown --cyan --danger --duration-fast --ease-standard --elevation-1 --fg-0 --fg-1 --fg-disabled --field-bg --field-border --font-sans --gray --green --info --leading-tight --line-2 --neutral --neutral-bg --orange --pink --purple --radius-full --radius-sm --red --ring --space-1 --space-2 --space-4 --space-5 --space-6 --state-disabled --state-hover --state-press --success --text-body --text-sm --warn --white --yellow

Accessibility

The thumb is role="slider" with aria-valuemin, aria-valuemax, and aria-valuenow kept in sync, never conveying value by position alone.
Full keyboard support: arrows move by step, PageUp/PageDown by ten steps, Home/End jump to min/max; the keys' default scroll is prevented.
Requires an accessible name: labelledby wins, then label; the binding warns at runtime when neither is present. hide-label keeps the label as the accessible name while visually hiding its text, so a host that renders its own label avoids announcing the name twice.
The show-value readout is aria-hidden so screen readers hear the value once via the thumb's aria-valuenow, not twice.
Pointer drag uses pointer capture so the thumb keeps tracking even when the cursor leaves the rail.
Focus is shown with a token ring and a transparent outline the forced-colors base rule promotes to a real system outline.
disabled blocks interaction, mutes the visuals, and pulls the thumb out of the tab order with aria-disabled.

Code

Ranges, sizes, and form association

A labeled slider, a stepped range, the compact size, a form-bound slider, and a disabled one.

<xoji-slider label="Volume" value="60"></xoji-slider>

<xoji-slider label="Brightness" min="0" max="100" step="5" value="40"></xoji-slider>

<xoji-slider size="sm" label="Compact" value="25"></xoji-slider>

<xoji-slider label="Opacity" name="opacity" value="80"></xoji-slider>

<xoji-slider label="Volume" value="60" show-value></xoji-slider>

<xoji-slider id="pct" label="Opacity" value="80" show-value></xoji-slider>
<script>
	document.getElementById("pct").format = (v) => v + "%";
</script>

<xoji-slider label="Volume" value="60" hide-label></xoji-slider>

<xoji-slider label="Locked" value="50" disabled></xoji-slider>
<script lang="ts">
	import { Slider } from "@xoji/svelte";

	let volume = $state(60);
</script>

<Slider label="Volume" bind:value={volume} />

<Slider label="Brightness" min={0} max={100} step={5} value={40} />

<Slider size="sm" label="Compact" value={25} />

<Slider label="Opacity" name="opacity" value={80} />

<Slider label="Volume" value={60} showValue />

<Slider label="Opacity" value={80} showValue format={(v) => `${v}%`} />

<Slider label="Volume" value={60} hideLabel />

<Slider label="Locked" value={50} disabled />
---
import { Slider } from "@xoji/astro";
---

<Slider label="Volume" value={60} />

<Slider label="Brightness" min={0} max={100} step={5} value={40} />

<Slider size="sm" label="Compact" value={25} />

<Slider label="Opacity" name="opacity" value={80} />

<Slider label="Volume" value={60} showValue />

<Slider label="Volume" value={60} hideLabel />

<Slider label="Locked" value={50} disabled />