Elastic slider
A slider that stretches like rubber past its ends, with a swaying value tag and detents the thumb clicks into.
pnpm dlx shadcn@latest add @uiarc/elastic-sliderLive · keyboard ready
- A single setting people drag to taste, such as volume, brightness, or opacity.
- Media and creative tools where a physical, tactile control fits the product.
- Values with a few common stops that should feel like detents.
- Use slider for dense forms and settings pages where a quiet control fits better.
- Use range-histogram-slider to pick a min and max over data.
- Use number-field or ruler-slider when the exact number matters more than the feel.
Installation
Add Elastic slider with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/elastic-sliderAdds the component and its local dependencies, and installs motion. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { ElasticSlider } from "@/components/arc/elastic-slider/elastic-slider";import { Volume1, Volume2 } from "lucide-react"; export function VolumeControl() { const [volume, setVolume] = useState(60); return ( <ElasticSlider label="Volume" value={volume} onValueChange={setVolume} marks={[0, { value: 50, label: "50%" }, 100]} format={value => `${value}%`} startIcon={<Volume1 size={16} />} endIcon={<Volume2 size={16} />} /> );}ElasticSlider
A single value slider that stretches like rubber past either end, swells the thumb under the finger, hangs a value tag that sways with speed, and treats marks as detents the thumb clicks into.
PropTypeDefaultDescription
labelRequiredstring–Visible label. It also names the thumb.valuenumber–Controlled value. Leave it out for uncontrolled use.defaultValuenumberminInitial value when uncontrolled.onValueChange(value: number) => void–Called on every change while dragging or pressing keys.onValueCommit(value: number) => void–Called once a drag is released, a key changes the value, or a mark label is clicked.minnumber0Lowest value.maxnumber100Highest value.stepnumber1Value increment. Values snap to it.largeStepnumber–Distance for PageUp, PageDown, and Shift with an arrow. Defaults to a tenth of the range.marks(number | { value: number; label?: string })[]–Detents. A dragged thumb clicks into each one and holds for about 7px. Labelled marks print under the track and can be clicked.format(value: number) => string–Formats the readout, the value tag, and aria-valuetext.showValuebooleantrueShows the value beside the label. The tag over the thumb still appears while dragging or using keys.startIconReactNode–Icon before the track. It is pushed outward when the track is pulled past the start.endIconReactNode–Icon after the track. It is pushed outward when the track is pulled past the end.namestring–Submits the value with a form through a hidden input.disabledbooleanfalseBlocks pointer and keyboard input and removes the thumb from the tab order.classNamestring–Extra class on the root.- ArrowRightorArrowUp
- Increases by one step.
- ArrowLeftorArrowDown
- Decreases by one step.
- Shift+ArroworPageUporPageDown
- Moves by largeStep.
- HomeorEnd
- Goes to min or max. At a limit, the track stretches toward the press and snaps back.
- The thumb is role="slider" with aria-valuemin, aria-valuemax, aria-valuenow, and aria-valuetext from format.
- The thumb is labelled by the visible label through aria-labelledby.
- The readout, value tag, icons, and mark labels are aria-hidden; the slider carries the value for assistive tech.
- Clicking a mark label is a pointer shortcut; the same values are reachable with keys.
- The track rubber-bands past either end with iOS-style resistance and springs back with the release velocity.
- The thumb swells to 1.28x while dragged; the value tag trails it on a soft spring and tilts with its speed.
- Detents pop their tick and, on touch devices that support it, give a short vibration.
- Reduced motion removes the stretch, sway, and tick pop; the thumb jumps to its value and the tag fades.
- The track fills its container; icons and the header stay on one row at any width.
- Touch drags use pointer capture, and detents add a short vibration where supported.
- Mark labels at the ends align to the track edges so they stay inside narrow containers.
- Thumb, fill, stretch, and tag are driven by motion values, so dragging does not re-render React per frame.
- Track width is measured with one ResizeObserver.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Choose it for one continuous value where the feel matters: volume, brightness, zoom, playback speed.
- Pass marks for values people aim for (0, 50, 100); they act as soft snaps without blocking values in between.
- Use onValueChange for live previews and onValueCommit for saves or network requests.
- For two thumbs or a range, use slider or range-histogram-slider instead.
The full library index for assistants is at /llms.txt.