Slider
v0.0.10
mix mishka.ui.gen.headless slider
Overview of the Phoenix and LiveView Headless Slider Component
The Mishka Chelekom Headless Slider ships zero opinionated styling - only the semantic markup, full WAI-ARIA wiring, pointer drag, and keyboard support (Arrow keys, Shift+Arrow / PageUp/PageDown, Home/End). Pass a single value or a list of values for a range with two or more thumbs; range thumbs respect min_steps_between_values and a configurable thumb_collision behavior. Every part - label, value readout, control, track, indicator, and thumb - is addressable through a *_class attribute, so you style it entirely with your own Tailwind classes while the accessibility and behavior keep working underneath.
The root takes class. The parts take label_class, value_class, control_class, track_class, indicator_class and thumb_class (every thumb). The label is drawn when label is set, and the value readout when show_value is.
Base UI Slider example (Phoenix headless)
Base UI Slider example (Phoenix headless)
<.slider
id="slider-hero"
value={25}
label="Volume"
control_class="flex w-56 touch-none items-center py-3 select-none"
track_class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"
indicator_class="bg-neutral-950 select-none dark:bg-white"
thumb_class="size-4 border border-neutral-950 bg-white select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950"
/>Range Slider
values takes a list, and each number is a thumb. thumb_labels gives every thumb its own accessible name. The filled indicator runs from the first thumb to the last.
Range Slider
<.slider
id="slider-range-slider"
values={[25, 45]}
thumb_labels={["Minimum value", "Maximum value"]}
control_class="flex w-56 touch-none items-center py-3 select-none"
track_class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"
indicator_class="bg-neutral-950 select-none dark:bg-white"
thumb_class="size-4 border border-neutral-950 bg-white select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950"
/>Edge Alignment
Edge Alignment
<.slider
id="slider-edge-alignment"
value={25}
label="Volume"
control_class="flex w-56 touch-none items-center py-3 select-none"
track_class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"
indicator_class="bg-neutral-950 select-none dark:bg-white"
thumb_class="size-4 border border-neutral-950 bg-white select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950"
/>Vertical
Vertical
<.slider
id="slider-vertical"
value={35}
orientation="vertical"
label="Volume"
control_class="flex touch-none select-none data-[orientation=vertical]:h-32 data-[orientation=vertical]:px-3"
track_class="bg-neutral-200 select-none dark:bg-neutral-800 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1"
indicator_class="bg-neutral-950 select-none dark:bg-white"
thumb_class="size-4 border border-neutral-950 bg-white select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950"
/>Slider example - label and value readout (Phoenix headless)
show_value draws the readout and label the label, both beside the control, so the root here is a two-column grid with the control spanning both. format takes Intl.NumberFormat options and locale a BCP-47 tag, and the hook keeps the readout current while a thumb moves.
Slider example - label and value readout (Phoenix headless)
<.slider
id="slider-readout"
values={[20, 60]}
format={%{style: "currency", currency: "USD", maximumFractionDigits: 0}}
locale="en-US"
label="Price range"
show_value
class="grid w-56 max-w-full grid-cols-2 gap-y-2"
label_class="text-sm font-normal text-neutral-950 dark:text-white"
value_class="text-right text-sm tabular-nums text-neutral-950 dark:text-white"
control_class="col-span-2 flex touch-none items-center py-3 select-none"
track_class="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800"
indicator_class="bg-neutral-950 select-none dark:bg-white"
thumb_class="size-4 border border-neutral-950 bg-white select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:border-white dark:bg-neutral-950"
/>Parts & data attributes
Each part carries a stable data-part and a structural chelekom-slider__* class you can target, plus orientation and drag state for styling.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | - | data-orientation, data-dragging, data-disabled | Carries the Slider hook; reads min/max/step/large_step/orientation/format from data-*; takes class. |
| Label | label | - | Accessible label, wired via aria-labelledby; drawn when label is set, and takes label_class. |
| Value | value | data-orientation | Formatted value readout, kept current as the thumbs move; drawn when show_value is set, and takes value_class. |
| Control | control | data-orientation, data-dragging, data-disabled | Press to jump the nearest thumb; drag to move it; takes control_class. |
| Track | track | data-orientation | The visual track the thumbs travel along; takes track_class. |
| Indicator | indicator | data-orientation | The filled interval from the first thumb (or min) to the last; takes indicator_class. |
| Thumb | thumb | role="slider", aria-orientation, aria-valuemin, aria-valuemax, aria-valuenow, aria-valuetext, data-index, data-orientation, data-dragging, data-disabled | One per value; contains a hidden input for form submission; takes thumb_class. |
| Input | input | - | Hidden value carrier (single → name, range → name[]). |
Accessibility
Follows the WAI-ARIA Slider (and multi-thumb) pattern: each thumb is a role="slider" element focusable with Tab. Arrow keys move by step (Up/Right increase), Shift+Arrow or PageUp/PageDown move by large_step, and Home/End jump to the minimum/maximum. Range thumbs keep their configured minimum gap and never cross past each other unexpectedly, per the chosen thumb_collision behavior.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | Yes | — |
name
|
string
| — | — | No | Name for the hidden form input(s) |
min
|
integer
|
0
| — | No | — |
max
|
integer
|
100
| — | No | — |
step
|
integer
|
1
| — | No | — |
large_step
|
integer
|
10
| — | No | Step for PageUp/Down and Shift+Arrow |
min_steps_between_values
|
integer
|
0
| — | No | Minimum gap (in steps) between range thumbs |
value
|
any
| — | — | No | Single-thumb value — accepts a Phoenix form value (integer, float or string) |
values
|
list
| — | — | No | Multi-thumb values (a range; overrides value) |
orientation
|
string
|
horizontal
| — | No | horizontal | vertical |
disabled
|
boolean
|
false
| — | No | Disable interaction (data-disabled) |
format
|
map
| — | — | No | Intl.NumberFormat options for aria-valuetext + value readout |
locale
|
string
| — | — | No | BCP-47 locale for formatting |
thumb_collision
|
string
|
push
| — | No | push | swap | none — range collision behaviour |
thumb_labels
|
list
| — | — | No | Per-thumb aria-labels (range) |
show_value
|
boolean
|
false
| — | No | Render the value readout |
label
|
string
| — | — | No | Accessible label |
form
|
string
| — | — | No | Form id owning the hidden input(s) |
on_change
|
string
| — | — | No | LiveView event pushed on change ({value}) |
on_commit
|
string
| — | — | No | LiveView event pushed on release/keyup ({value}) |
class
|
any
| — | — | No | — |
control_class
|
any
| — | — | No | Extra classes for the control part |
track_class
|
any
| — | — | No | Extra classes for the track part |
indicator_class
|
any
| — | — | No | Extra classes for the indicator (filled interval) |
thumb_class
|
any
| — | — | No | Extra classes for each thumb |
label_class
|
any
| — | — | No | — |
value_class
|
any
| — | — | No | — |
rest
|
global
| — | — | No | — |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
slider
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless slider