Selection
Slider
MD3 Expressive slider.
import { Slider } from 'omaris' Examples
Basic
wave ripples the fill while you drag — for a value set by feel, like volume. A plain track for a plainer setting.
<script lang="ts"> import { Slider } from 'omaris'; let volume = $state(64);</script><div class="w-full max-w-md"> <Slider bind:value={volume} wave label="Volume" showValue /></div> Steps and ticks
A step snaps the handle; ticks draws where it will land.
<script lang="ts"> import { Slider } from 'omaris'; let rating = $state(3); let zoom = $state(100);</script><div class="flex w-full max-w-md flex-col gap-8"> <Slider bind:value={rating} min={1} max={5} step={1} ticks label="Rating" showValue /> <Slider bind:value={zoom} min={50} max={200} step={25} label="Zoom" showValue format={(v) => `${v}%`} /></div> Range
Two handles on one track — a price range, a time window.
Handles cannot cross.
<script lang="ts"> import { RangeSlider } from 'omaris'; let price = $state<[number, number]>([20, 80]);</script><div class="w-full max-w-md"> <RangeSlider bind:value={price} label="Price" showValue format={(v) => `$${v}`} supportingText="Handles cannot cross." /></div> Elastic
elastic lets the ends give: drag past either end and the whole track stretches after the finger, less and less the further it goes, and springs back with a small bounce when you let go. The value is already at its limit; the stretch is how the track says so without a wall.
<script lang="ts"> import { Slider } from 'omaris'; let brightness = $state(88); let volume = $state(12);</script><div class="flex w-full max-w-md flex-col gap-6"> <Slider bind:value={brightness} elastic label="Brightness" showValue /> <Slider bind:value={volume} elastic wave size="sm" label="Volume" showValue /></div> Sizes and orientation
Three thicknesses, and a vertical track for a mixer or a level.
<script lang="ts"> import { Slider } from 'omaris'; let a = $state(30); let b = $state(55); let c = $state(80); let level = $state(70);</script><div class="flex w-full items-start gap-10"> <div class="flex min-w-0 flex-1 flex-col gap-6"> <Slider bind:value={a} size="sm" ariaLabel="Small" /> <Slider bind:value={b} ariaLabel="Medium" /> <Slider bind:value={c} size="lg" wave="always" ariaLabel="Large, always waving" /> </div> <div class="h-40"> <Slider bind:value={level} orientation="vertical" size="lg" ariaLabel="Level" /> </div></div> Overridden
Every part is reachable, so a slider can wear a different accent entirely.
<script lang="ts"> import { Slider } from 'omaris'; let heat = $state(45);</script><div class="w-full max-w-md"> <Slider bind:value={heat} tone="warning" label="Roast" showValue format={(v) => `${v}°`} classes={{ label: 'uppercase tracking-wide text-xs' }} /></div> When to use it
Use it for
- A value set by feel, like volume, brightness, opacity or zoom, where the effect shows as you drag.
showValueorbubblefor the readout. - Coarse choices along a scale:
stepwithticks, andformatto name the stops ("Low / Medium / High", "1x … 4x"). - A window between two ends, like a price bracket or working hours:
RangeSlider, withminDistanceso the handles cannot meet. - A media track:
waveripples while dragging,wave="always"while it plays,size="sm".size="lg"withorientation="vertical"for a dimmer or a fader.
Not for
- A number that must be exact, like a quantity, a port or a price → Text Field
type="number"or Price Input. - A handful of named options → Segmented Button or Radio. A slider with three stops is a radio.
- A value that cannot be changed → Progress or Gauge.
- A colour → Color Picker, which is these sliders already wired.
Do
- Give it a
label, orariaLabelwhen the label is elsewhere. A range takes two, one per handle. - Do the expensive work (the save, the fetch) in
onchange. Keeponinputfor what must track the drag, like a preview. - Pass
formatwhenever the raw number means nothing alone: "40%", "$120", "3:45". - Set
namewhen the value should submit with the form. One hidden input per handle.
Don't
- Use a step so fine the handle lands anywhere. On a phone a thumb cannot hit 37 of 100. Show the value and let the arrow keys finish.
- Ask for
tickson hundreds of steps. They switch off above 30. - Put
wave="always"on anything that is not playing. - Hide both the label and the value. A bare track is decoration.
API
Slider
MD3 Expressive slider.
For two handles, see RangeSlider.
import { Slider } from 'omaris' <Slider bind:value label="Volume" showValue /><Slider bind:value wave /> <!-- ripples while dragging --><Slider bind:value wave="always" /> <!-- a playing media track --><Slider bind:value orientation="vertical" size="lg" /> Props
value bindableDefaults to 0
number Bindable.
oninput (value: number) => void Fires on every change.
onchange (value: number) => void Fires when a drag ends or a key is pressed — the commit moment.
min number max number step number minDistance number Smallest allowed gap between the two handles of a range.
tone SliderTone size SliderSize orientation SliderOrientation wave boolean | 'always' Ripple a wave through the filled part while it's being dragged. 'always' keeps it moving — for a media player that's playing.
label string Label above the track.
supportingText string Helper line below the track.
showValue boolean Show the current value beside the label.
bubble boolean | 'always' Float the value over the handle while dragging; 'always' keeps it up.
ticks boolean Draw a stop dot at every step. Ignored above 30 steps.
format (value: number) => string Turns a number into display text — "40%", "$12".
name string Submit the value(s) with the surrounding form.
elastic boolean Let the track stretch when dragged past either end, and spring back on release.
haptics boolean A haptic tick on every step, and a firmer bump at either end. Follows the shared haptics store; false opts this slider out.
sound boolean A sound cue as the handle passes each step, and a duller one at the ends. Follows the shared sound store; false opts this slider out.
disabled boolean Inside a Field, defaults to the field's.
ariaLabel string | string[] Accessible name for each handle, when there's no visible label.
class string classes SliderClasses Per-part Tailwind overrides. class still covers the root.
ref bindableDefaults to null
HTMLDivElement | null RangeSlider
Two handles, one track — a price range, a time window.
The handles can't cross; minDistance keeps them apart.
import { RangeSlider } from 'omaris' <RangeSlider bind:value={[20, 80]} label="Price" format={(v) => `$${v}`} showValue /> Props
value bindableDefaults to [0, 100]
[number, number] [low, high]. Bindable.
oninput (value: [number, number]) => void onchange (value: [number, number]) => void min number max number step number minDistance number Smallest allowed gap between the two handles of a range.
tone SliderTone size SliderSize orientation SliderOrientation wave boolean | 'always' Ripple a wave through the filled part while it's being dragged. 'always' keeps it moving — for a media player that's playing.
label string Label above the track.
supportingText string Helper line below the track.
showValue boolean Show the current value beside the label.
bubble boolean | 'always' Float the value over the handle while dragging; 'always' keeps it up.
ticks boolean Draw a stop dot at every step. Ignored above 30 steps.
format (value: number) => string Turns a number into display text — "40%", "$12".
name string Submit the value(s) with the surrounding form.
elastic boolean Let the track stretch when dragged past either end, and spring back on release.
haptics boolean A haptic tick on every step, and a firmer bump at either end. Follows the shared haptics store; false opts this slider out.
sound boolean A sound cue as the handle passes each step, and a duller one at the ends. Follows the shared sound store; false opts this slider out.
disabled boolean Inside a Field, defaults to the field's.
ariaLabel string | string[] Accessible name for each handle, when there's no visible label.
class string classes SliderClasses Per-part Tailwind overrides. class still covers the root.
ref bindableDefaults to null
HTMLDivElement | null