Skip to content
Docs

Slider

An input where the user selects a value from within a given range.

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>
Can be controlled or uncontrolled.
Supports multiple thumbs.
Supports a minimum value between thumbs.
Supports touch or click on track to update value.
Supports Right to Left direction.
Full keyboard navigation.

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
Type any Default [0]
dir
Type string Default "ltr"
disabled
Type boolean Default false
id
Type string Default
inverted
Type boolean Default false
max
Type integer Default 100
min
Type integer Default 0
min_steps_between_thumbs
Type integer Default 0
name
Type string Default nil
on_value_change
Type string Default nil
orientation
Type string Default "horizontal"
step
Type integer Default 1
value
Type 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
Type 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.