Slider

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

Stimulus: shadcn--slider
slider/default
<div class="w-[60%] space-y-2">
  <div class="flex justify-between">
    <span class="text-sm font-medium">Value</span>
    <span id="default-slider-value" class="text-sm text-muted-foreground">33</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 33, data: { "output-target": "default-slider-value", "output-format": "{value}" }) %>
</div>

Installation

Add the component to your project:

rails generate shadcn:add slider

Usage

<div class="w-[60%] space-y-2">
  <div class="flex justify-between">
    <span class="text-sm font-medium">Value</span>
    <span id="default-slider-value" class="text-sm text-muted-foreground">33</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 33, data: { "output-target": "default-slider-value", "output-format": "{value}" }) %>
</div>

Examples

Default

Value 33
<div class="w-[60%] space-y-2">
  <div class="flex justify-between">
    <span class="text-sm font-medium">Value</span>
    <span id="default-slider-value" class="text-sm text-muted-foreground">33</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 33, data: { "output-target": "default-slider-value", "output-format": "{value}" }) %>
</div>

With Synced Label

Use data-output-target and data-output-format to sync value labels.

75%
<div class="space-y-4 w-full max-w-md">
  <div class="flex justify-between">
    <%= render Shadcn::LabelComponent.new { "Volume" } %>
    <span id="volume-label" class="text-sm text-muted-foreground">75%</span>
  </div>
  <%= render Shadcn::SliderComponent.new(
    value: 75,
    max: 100,
    data: { "output-target": "volume-label", "output-format": "{value}%" }
  ) %>
</div>

Two-Way Input Binding

Use data-input-target to bind a slider to a number input for two-way sync. Changes to either element update the other.

Change the slider or type a value in the input - both stay in sync.

<div class="space-y-4 w-full max-w-md">
  <div class="flex items-center justify-between gap-4">
    <%= render Shadcn::LabelComponent.new(for: "brightness-input") { "Brightness" } %>
    <%= render Shadcn::InputComponent.new(
      id: "brightness-input",
      type: "number",
      value: 75,
      min: 0,
      max: 100,
      class_name: "w-20 text-center"
    ) %>
  </div>
  <%= render Shadcn::SliderComponent.new(
    value: 75,
    max: 100,
    data: {
      "input-target": "brightness-input"
    }
  ) %>
  <p class="text-xs text-muted-foreground">
    Change the slider or type a value in the input - both stay in sync.
  </p>
</div>

Custom Range

Use min and max to set a custom range.

20°C
10°C 30°C
<div class="space-y-4 w-full max-w-md">
  <div class="flex justify-between">
    <%= render Shadcn::LabelComponent.new { "Temperature" } %>
    <span id="temp-label" class="text-sm text-muted-foreground">20°C</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 20, min: 10, max: 30, data: { "output-target": "temp-label", "output-format": "{value}°C" }) %>
  <div class="flex justify-between text-xs text-muted-foreground">
    <span>10°C</span>
    <span>30°C</span>
  </div>
</div>

With Steps

Use step to set discrete intervals.

3 stars
1 2 3 4 5
<div class="space-y-4 w-full max-w-md">
  <div class="flex justify-between">
    <%= render Shadcn::LabelComponent.new { "Rating" } %>
    <span id="rating-label" class="text-sm text-muted-foreground">3 stars</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 3, min: 1, max: 5, step: 1, data: { "output-target": "rating-label", "output-format": "{value} stars" }) %>
  <div class="flex justify-between text-xs text-muted-foreground">
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
  </div>
</div>

Decimal Steps

Use decimal values for step for fine-grained control.

0.5
0 0.5 1
<div class="space-y-4 w-full max-w-md">
  <div class="flex justify-between">
    <%= render Shadcn::LabelComponent.new { "Opacity" } %>
    <span id="opacity-label" class="text-sm text-muted-foreground">0.5</span>
  </div>
  <%= render Shadcn::SliderComponent.new(value: 0.5, min: 0, max: 1, step: 0.1, data: { "output-target": "opacity-label", "output-format": "{value}" }) %>
  <div class="flex justify-between text-xs text-muted-foreground">
    <span>0</span>
    <span>0.5</span>
    <span>1</span>
  </div>
</div>

Disabled

<div class="space-y-4 w-full max-w-md">
  <%= render Shadcn::LabelComponent.new { "Disabled Slider" } %>
  <%= render Shadcn::SliderComponent.new(value: 50, disabled: true) %>
</div>

In a Form

Audio Settings

Adjust your audio preferences.

80%
60%
90%
<%= render Shadcn::CardComponent.new(class_name: "w-full max-w-md") do |card| %>
  <% card.with_header do |header| %>
    <% header.with_title { "Audio Settings" } %>
    <% header.with_description { "Adjust your audio preferences." } %>
  <% end %>
  <% card.with_content do %>
    <div class="space-y-6">
      <div class="space-y-2">
        <div class="flex justify-between">
          <%= render Shadcn::LabelComponent.new { "Master Volume" } %>
          <span id="master-vol-label" class="text-sm text-muted-foreground">80%</span>
        </div>
        <%= render Shadcn::SliderComponent.new(name: "master_volume", value: 80, data: { "output-target": "master-vol-label", "output-format": "{value}%" }) %>
      </div>
      <div class="space-y-2">
        <div class="flex justify-between">
          <%= render Shadcn::LabelComponent.new { "Music" } %>
          <span id="music-vol-label" class="text-sm text-muted-foreground">60%</span>
        </div>
        <%= render Shadcn::SliderComponent.new(name: "music_volume", value: 60, data: { "output-target": "music-vol-label", "output-format": "{value}%" }) %>
      </div>
      <div class="space-y-2">
        <div class="flex justify-between">
          <%= render Shadcn::LabelComponent.new { "Sound Effects" } %>
          <span id="sfx-vol-label" class="text-sm text-muted-foreground">90%</span>
        </div>
        <%= render Shadcn::SliderComponent.new(name: "sfx_volume", value: 90, data: { "output-target": "sfx-vol-label", "output-format": "{value}%" }) %>
      </div>
    </div>
  <% end %>
  <% card.with_footer do %>
    <%= render Shadcn::ButtonComponent.new { "Save Settings" } %>
  <% end %>
<% end %>

Rating

slider/rating
<%= render Shadcn::SliderComponent.new( name: "rating", value: 3, min: 1, max: 5, step: 1 ) %>

Volume Control

slider/volume
<%= render Shadcn::SliderComponent.new( name: "volume", value: 75, min: 0, max: 100, step: 5 ) %>

Temperature

slider/temperature
<%= render Shadcn::SliderComponent.new( name: "temperature", value: 20.5, min: 15.0, max: 30.0, step: 0.5 ) %>

With Label

slider/with_label
<%= render Shadcn::SliderComponent.new(name: "volume", value: 50, max: 100) %>

API Reference

API Reference

Prop Type Default Description
name String nil Input name for form submission
value Numeric 0 Current slider value
min Numeric 0 Minimum value
max Numeric 100 Maximum value
step Numeric 1 Step increment
disabled Boolean false Whether the slider is disabled
class_name String nil Additional CSS classes to apply

Stimulus Controller

This component requires JavaScript. The Stimulus controller shadcn--slider provides interactivity.

Updates the slider's visual fill and supports one-way output sync and two-way input binding.

Installation

Add to your config/importmap.rb:

pin "shadcn", to: "index.esm.js"

Then in your app/javascript/controllers/index.js:

import { Application } from "@hotwired/stimulus"
import { registerShadcnControllers } from "shadcn"

const application = Application.start()
registerShadcnControllers(application)

Or import just this controller:

import SliderController from "shadcn-rails-stimulus/controllers/slider_controller"

application.register("shadcn--slider", SliderController)

Targets

Name Description
output Element to display the current value (auto-synced on change)

Values

Name Type Default Description
outputFormat String "{value}" Format string for output ({value} and {percent} placeholders)

Actions

Action Description
updateStyle Updates CSS fill, syncs output target, and updates linked input on change

TypeScript

Type definitions are included. Import types as needed:

import type { SliderController } from "shadcn-rails-stimulus"

Data Attributes

These attributes can be added to the slider's native <input type="range"> element:

API Reference

Prop Type Default Description
data-output-target String nil ID of element to display value (one-way: slider → output)
data-output-format String {value} Format string with {value} and {percent} placeholders
data-input-target String nil ID of input element for two-way binding (slider ↔ input)

Accessibility

  • Uses native <input type="range"> for built-in accessibility
  • Keyboard navigation: Arrow keys to adjust value
  • Always pair with a visible label or aria-label
  • Consider showing the current value for screen readers