Skip to main content
WireKit
Copy for LLM

Slider

The <x-wirekit::slider> component is a styled wrapper around the native <input type="range">. It provides accent-colored track styling, size variants, and an optional live value display while preserving full browser accessibility.

Usage

Basic Slider

Width

The slider fills its parent width. Constrain it via the parent element:

<div class="max-w-sm">
    <x-wirekit::slider name="volume" :min="0" :max="100" :value="50" />
</div>

Size Variants

Three Sizes

Step Marks

Pass marks to render tick marks along the track. A plain list ([0, 25, 50, 75, 100]) draws ticks at those positions; a value-to-label map ([0 => 'Min', 100 => 'Max']) adds labels underneath.

Slider with labeled marks

Marks that carry a meaning

A third shape gives a mark a description as well as a label — for the case where the positions mean something and the label alone cannot say what:

Marks with descriptions

Hover a tick to read its meaning. This exists because the alternative is worse than it sounds: without it, a reader who wants to know what a position means has to move the slider to find out — changing the very thing they were still deciding about.

The description reaches a reader two ways, and both are needed. It becomes the tick's title, which is a pointer affordance — and there is no hover on touch, so title alone would hide the meaning from the readers most likely to be guessing at it. So it is also what the slider announces: as you move through the positions, a screen reader reads the description of the one you are on rather than the bare number. One position at a time, not every mark at once.

It also becomes what the slider announces. Where a mark has both, the description wins over the label: the label is what you see on the tick (−2), the description is what the position means (Single verdict), and the second is the useful one to hear. valueTextMap still overrides everything if you want to decouple the two entirely.

Both older shapes are untouched — a list and a label map render exactly as before, with no title and no description. The new shape is opt-in per mark, and a mark may carry a description with no label at all.

Value Tooltip

Set tooltip to float a value bubble above the thumb that follows it as the user drags — handy when there's no room for a persistent value display.

Slider with a value tooltip

Custom Step

<x-wirekit::slider name="price" :min="0" :max="1000" :step="25" :value="250" :show-value="true" />

Livewire Integration

<x-wirekit::slider> keeps its displayed value in internal state seeded from the value prop, so when binding with Livewire pass the bound property as :value alongside wire:model to seed the initial display:

<x-wirekit::slider wire:model.live="volume" :value="$volume" min="0" max="100" />

Without :value the slider sits at min until the user interacts; wire:model keeps it in sync afterward. This is the framework-agnostic seeding pattern WireKit's stateful controls share — it works in plain Blade forms too.

Optimistic UI

Pass the name of the Livewire method the slider should call and the new value is shown straight away, while it goes:

<x-wirekit::slider
    name="volume"
    label="Volume"
    :value="$volume"
    optimistic="saveVolume"
/>

Load wirekit-optimistic.js alongside whichever bundle you already use — below it, in your layout:

@wirekitScripts
<script src="{{ asset('vendor/wirekit/wirekit-optimistic.js') }}"></script>

Try it

The demo below runs the real path: the change shows immediately, the outline says it is provisional, and the server's answer either confirms it silently or takes it back.

Optimistic slider — accepted, refused, and a slow answer

The <livewire:demos.…> wrapper above exists only on this site — it supplies the demo methods so the page can show a real round trip. The block under it is what you write.

It sends when the gesture ends, not while it runs. Dragging produces a value per frame, and sending each one would be a hundred requests for a single decision. So the value goes once, when you let go — and immediately on an arrow key, because one keypress is already a finished decision. There is no settle delay anywhere in this: a timer would make the same gesture behave differently on a fast machine than on a slow one.

A refusal puts the thumb back where the gesture started — not where you released it. Both the announced value and the control itself return, so nothing is left showing a position the server declined.

Props

Prop Type Default Description
name string|null null Form field name
error string|null null Validation message. Rendered below the control, announced politely, and wired with aria-invalid + aria-describedby
hint string|null null Helper text below the control. An error replaces it — one message region, so the two cannot stack
id string|null auto-generated Element id
min int 0 Minimum value
max int 100 Maximum value
step int|float 1 Increment step
value int|null min Initial value
size string 'md' 'sm', 'md', 'lg'
showValue bool false Show live value next to slider
marks array [] Tick marks — a list of positions ([0, 50, 100]), a position-to-label map ([0 => 'Min', 100 => 'Max']), or a map to ['label' => …, 'description' => …] for positions whose meaning the label cannot carry. See Step Marks.
valueTextMap array|null null A value => spoken-text map for aria-valuetext, decoupled from the visual ticks — show numeric ticks but announce semantic meaning ([1 => 'Low', 5 => 'High']). A caller aria-valuetext binding wins over both
tooltip bool false Float a value bubble above the thumb that follows it
disabled bool false Disabled state
optimistic string|null null Livewire method to call when the gesture ends, showing the change before the server answers
optimisticArgs array [] Extra arguments appended to the optimistic action call, after the new value — the row this control belongs to.
scope string|null null Scoped personalization key

Accessibility

  • Wraps the native <input type="range"> — inherits all browser a11y features
  • Arrow keys move by step, Home/End jump to min/max, PageUp/PageDown move by larger increments
  • Live value display uses aria-live="polite" for non-intrusive AT announcements
  • Disabled state via native disabled attribute

Keyboard Interaction

Key Action
Tab Move focus to the slider thumb
ArrowLeft / ArrowDown Decrease the value by step
ArrowRight / ArrowUp Increase the value by step
PageDown Decrease by a larger amount (typically 10× step)
PageUp Increase by a larger amount
Home Jump to min
End Jump to max

Pitfalls

  • Don't use a slider for precise numeric input. Use <x-wirekit::number-input> with a stepper. Sliders excel at fuzzy / relative values (volume, opacity) where exact numbers don't matter.
  • Don't omit a numeric label. Touch users can't see the thumb's exact position — pair the slider with a live-updating value display.
  • A dragged slider with wire:model.live floods the server. The native range input fires a change on every step during a drag, so .live sends one Livewire round-trip per step. Use wire:model.live.debounce.300ms to coalesce them, or wire:model.lazy to sync only when the drag ends.

Design Tokens

The slider relies primarily on the native <input type="range"> rendering for the track and thumb, which inherits the browser-default accent color. The wrapper around the value display uses these tokens:

Token Used for
--text-wk-sm Live value font size
--color-wk-text Live value text
--padding-wk-x-sm Live value pill padding
--opacity-wk-disabled Disabled visual weight

Config Defaults

The defaults live in config/wirekit.php under components.slider. Override them globally:

'components' => [
    'slider' => ['min' => 0, 'max' => 100, 'step' => 1, 'size' => 'md'],
],

Further Reading

Was this page helpful?

Thanks — that helps.

Voting requires cookies or local storage. What we store