An input where the user selects a value from within a given range.
<form>
<Slider.root
id="slider-primitive"
class="DemoSliderRoot"
default_value={[50]}
max={100}
step={1}
>
<Slider.track class="DemoSliderTrack">
<Slider.range class="DemoSliderRange" />
</Slider.track>
<Slider.thumb class="DemoSliderThumb" index={0} aria-label="Volume" />
</Slider.root>
</form>
.DemoSliderRoot {
position: relative;
display: flex;
align-items: center;
user-select: none;
touch-action: none;
width: 200px;
height: 20px;
}
.DemoSliderTrack {
background-color: var(--black-a10);
position: relative;
flex-grow: 1;
border-radius: 9999px;
height: 3px;
}
.DemoSliderRange {
position: absolute;
background-color: white;
border-radius: 9999px;
height: 100%;
}
.DemoSliderThumb {
display: block;
width: 20px;
height: 20px;
background-color: white;
box-shadow: 0 2px 10px var(--black-a7);
border-radius: 10px;
}
.DemoSliderThumb:hover {
background-color: var(--violet-3);
}
.DemoSliderThumb:focus {
outline: none;
box-shadow: 0 0 0 5px var(--black-a8);
}
Anatomy
Import all parts and piece them together.
<Slider.root id="…">
<Slider.track>
<Slider.range />
</Slider.track>
<Slider.thumb index={0} />
</Slider.root>
Anatomy
-
Root - Contains all the parts of a slider.
-
Track - The track that contains the range.
-
Range - The filled portion of the track.
-
Thumb - A draggable thumb. Render one per value; set `index` for each.
API Reference
Root
Contains all the parts of a slider.
Use value with on_value_change for controlled state in LiveView:
<Slider.root id="volume" value={@volume} on_value_change="volume_change" min={0} max={100}>
…
</Slider.root>
def handle_event("volume_change", %{"value" => values}, socket) do
{:noreply, assign(socket, volume: values)}
end
| Prop | Type | Default | Description |
|---|---|---|---|
default_value
|
any
|
[0]
|
|
dir
|
string
|
"ltr"
|
|
disabled
|
boolean
|
false
|
|
id
|
string
|
—
|
|
inverted
|
boolean
|
false
|
|
max
|
integer
|
100
|
|
min
|
integer
|
0
|
|
min_steps_between_thumbs
|
integer
|
0
|
|
name
|
string
|
nil
|
|
on_value_change
|
string
|
nil
|
|
orientation
|
string
|
"horizontal"
|
|
step
|
integer
|
1
|
|
value
|
any
|
nil
|
default_value
any
Default
[0]
dir
string
Default
"ltr"
disabled
boolean
Default
false
id
string
Default
—
inverted
boolean
Default
false
max
integer
Default
100
min
integer
Default
0
min_steps_between_thumbs
integer
Default
0
name
string
Default
nil
on_value_change
string
Default
nil
orientation
string
Default
"horizontal"
step
integer
Default
1
value
any
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-disabled]
|
|
Present when disabled. |
[data-orientation]
|
horizontal | vertical
|
The orientation of the slider. |
Track
The track that contains the Slider.range.
| Prop | Type | Default | Description |
|---|
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-disabled]
|
|
Present when disabled. |
[data-orientation]
|
horizontal | vertical
|
The orientation of the slider. |
Range
The range part. Must live inside Slider.track.
| Prop | Type | Default | Description |
|---|
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-disabled]
|
|
Present when disabled. |
[data-orientation]
|
horizontal | vertical
|
The orientation of the slider. |
Thumb
A draggable thumb. You can render multiple thumbs—pass a distinct index for each (0-based).
| Prop | Type | Default | Description |
|---|---|---|---|
index
|
integer
|
0
|
index
integer
Default
0
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-disabled]
|
|
Present when disabled. |
[data-orientation]
|
horizontal | vertical
|
The orientation of the slider. |
Examples
Vertical orientation
Use the orientation attribute to create a vertical slider.
<Slider.root id="slider-vertical" class="DemoSliderRoot" default_value={[50]} orientation="vertical">
<Slider.track class="DemoSliderTrack">
<Slider.range class="DemoSliderRange" />
</Slider.track>
<Slider.thumb class="DemoSliderThumb" index={0} aria-label="Volume" />
</Slider.root>
Style vertical layout with [data-orientation="vertical"] on the root, track, and range—see assets/css/primitives/slider.css.
Create a range
Add multiple thumbs and values to create a range slider.
<Slider.root id="slider-range" default_value={[25, 75]}>
<Slider.track>
<Slider.range />
</Slider.track>
<Slider.thumb index={0} aria-label="Minimum" />
<Slider.thumb index={1} aria-label="Maximum" />
</Slider.root>
Define step size
Use the step attribute to increase the stepping interval.
<Slider.root id="slider-step" default_value={[50]} step={10}>
<Slider.track>
<Slider.range />
</Slider.track>
<Slider.thumb index={0} />
</Slider.root>
Prevent thumb overlap
Use min_steps_between_thumbs to avoid thumbs with equal values.
<Slider.root id="slider-min-steps" default_value={[25, 75]} step={10} min_steps_between_thumbs={1}>
<Slider.track>
<Slider.range />
</Slider.track>
<Slider.thumb index={0} />
<Slider.thumb index={1} />
</Slider.root>
Accessibility
Adheres to the Slider WAI-ARIA design pattern.
Keyboard Interactions
Keyboard Interactions
| Key | Description |
|---|---|
ArrowRight
|
Increments/decrements by the `step` value depending on `orientation`. |
ArrowLeft
|
Increments/decrements by the `step` value depending on `orientation`. |
ArrowUp
|
Increases the value by the `step` amount. |
ArrowDown
|
Decreases the value by the `step` amount. |
PageUp
|
Increases the value by a larger `step`. |
PageDown
|
Decreases the value by a larger `step`. |
Shift + ArrowUp
|
Increases the value by a larger `step`. |
Shift + ArrowDown
|
Decreases the value by a larger `step`. |
Home
|
Sets the value to its minimum. |
End
|
Sets the value to its maximum. |
Custom APIs
Create your own API by abstracting the primitive parts into your own component.
Abstract all parts
This example abstracts all of the Slider parts so it can be used as a self-closing element.
Usage
<.slider id="volume" default_value={[25]} />
Implementation
def slider(assigns) do
values = assigns[:value] || assigns[:default_value] || [0]
assigns = assign(assigns, :values, List.wrap(values))
~H"""
<Slider.root id={@id} value={@value} default_value={@default_value} {@rest}>
<Slider.track>
<Slider.range />
</Slider.track>
<%= for {_, index} <- Enum.with_index(@values) do %>
<Slider.thumb index={index} />
<% end %>
</Slider.root>
"""
end
Caveats
Mouse events are not fired
Because of a known limitation in pointer event handling, onMouseDown and onMouseUp on the root may not fire as expected:
<Slider.root id="slider-mouse" phx-hook="MySliderHook">
…
</Slider.root>
We recommend using pointer events instead (for example phx-hook handlers for pointerdown / pointerup). Regardless of the above limitation, pointer events are better suited for cross-platform handling because they cover mouse, touch, and pen input.