Skip to content
omaris

Selection

Slider

MD3 Expressive slider.

import { Slider } from 'omaris'
Learn

Examples

Basic

wave ripples the fill while you drag — for a value set by feel, like volume. A plain track for a plainer setting.

Volume 64
<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.

Rating 3
Zoom 100%
<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.

Price $20 – $80

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.

Brightness 88
Volume 12
<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.

Roast 45°
<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. showValue or bubble for the readout.
  • Coarse choices along a scale: step with ticks, and format to name the stops ("Low / Medium / High", "1x … 4x").
  • A window between two ends, like a price bracket or working hours: RangeSlider, with minDistance so the handles cannot meet.
  • A media track: wave ripples while dragging, wave="always" while it plays, size="sm". size="lg" with orientation="vertical" for a dimmer or a fader.

Not for

Do

  • Give it a label, or ariaLabel when the label is elsewhere. A range takes two, one per handle.
  • Do the expensive work (the save, the fetch) in onchange. Keep oninput for what must track the drag, like a preview.
  • Pass format whenever the raw number means nothing alone: "40%", "$120", "3:45".
  • Set name when 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 ticks on 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 bindable

Defaults 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 bindable

Defaults 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 bindable

Defaults 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 bindable

Defaults to null

HTMLDivElement | null