Elastic Slider
Slider with elastic rubber-band drag and magnetic snap feedback.
Last updated August 7, 2026
CreditsModifiedPublished
Copied from Josh Puckett — Interface Craft and Chánh Đại — Elastic Slider.
- Value 0 now maps to the reading start (right edge in RTL) instead of always the physical left, matching a native <input type="range"> in RTL browsers
- Arrow key direction follows reading direction: ArrowRight decreases the value in RTL instead of always increasing it
- Fill, handle, hash marks, label, and value text use logical start/end positioning instead of left/right
Overview
"use client"
import { useState } from "react"
import { ElasticSlider } from "@/components/ui/elastic-slider"
export function ElasticSliderDemoExample() {
const [opacity, setOpacity] = useState(0.5)
return (
<div className="flex w-50 flex-col gap-4">
<ElasticSlider
label="Opacity"
min={0}
max={1}
value={opacity}
onValueChange={setOpacity}
/>
<ElasticSlider
label="Blur"
min={0}
max={100}
step={1}
defaultValue={20}
formatValue={(v) => `${v}px`}
/>
<ElasticSlider
label="Saturation"
min={0}
max={10}
step={0.1}
defaultValue={8}
/>
</div>
)
}Installation
$ npx shadcn@latest add https://ui.persian-labs.ir/r/elastic-slider.jsonUsage
import { ElasticSlider } from "@/components/elastic-slider"
const [opacity, setOpacity] = useState(0.5)
<ElasticSlider
label="Opacity"
min={0}
max={1}
value={opacity}
onValueChange={setOpacity}
/>Uncontrolled:
<ElasticSlider label="Opacity" min={0} max={1} defaultValue={0.5} />Range slider
Need two handles on one track — a min and a max, like a price filter? Use Elastic Range Slider instead.
RTL
"use client"
import { useState } from "react"
import { ElasticSlider } from "@/components/ui/elastic-slider"
export function ElasticSliderRtlExample() {
const [price, setPrice] = useState(50)
return (
<div className="w-50">
<ElasticSlider
label="قیمت"
min={0}
max={100}
step={1}
value={price}
onValueChange={setPrice}
formatValue={(v) => `${v} هزار تومان`}
/>
</div>
)
}Keyboard
Keys
| Prop | Type | Default | Description |
|---|---|---|---|
| ArrowRight / ArrowUp | — | — | Increase by one step. ArrowRight decreases instead in RTL. |
| ArrowLeft / ArrowDown | — | — | Decrease by one step. ArrowLeft increases instead in RTL. |
| Shift + Arrow | — | — | Increase or decrease by step × 10. |
| Home | — | — | Jump to min. |
| End | — | — | Jump to max. |
API Reference
ElasticSlider
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | required | Label shown inside the track. |
| value | number | undefined | Controlled value. Use together with onValueChange. |
| defaultValue | number | min | Initial value for uncontrolled mode. |
| onValueChange | (value: number) => void | — | Called with the new value on drag, click, or key press. |
| min | number | 0 | Minimum value. |
| max | number | 1 | Maximum value. |
| step | number | 0.01 | Smallest increment. |
| formatValue | (value: number) => string | value.toFixed(...) | Format the displayed value, based on step's decimal precision by default. |
| aria-label | string | label | Accessible name. Falls back to label. |