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@4.23.0 add @xzero-ui/elastic-slider- Type: Component (inputs)
- Access: Free, open source
- Page: https://ui.xzero.co.uk/components/elastic-slider
- Markdown: https://ui.xzero.co.uk/components/elastic-slider/markdown
- Registry item: https://mcp.xzero.co.uk/r/elastic-slider.json
- Source file:
registry/components/elastic-slider/elastic-slider.tsx - Dependencies: motion
- Keywords: inputs, new, elastic slider, rubber band slider, react slider, volume slider, slider with detents, stretchy slider, ios slider, animated range input
When to use
- 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.
When not to use
- 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
Register both Xzero UI namespaces in your project's components.json:
{
"registries": {
"@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
"@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
}
}
npx shadcn@4.23.0 add @xzero-ui/elastic-slider
Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.
Usage
import { ElasticSlider } from "@/components/xzero/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} />}
/>
);
}
API reference
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.
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | – | Visible label. It also names the thumb. |
value | number | – | Controlled value. Leave it out for uncontrolled use. |
defaultValue | number | min | Initial 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. |
min | number | 0 | Lowest value. |
max | number | 100 | Highest value. |
step | number | 1 | Value increment. Values snap to it. |
largeStep | number | – | 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. |
showValue | boolean | true | Shows the value beside the label. The tag over the thumb still appears while dragging or using keys. |
startIcon | ReactNode | – | Icon before the track. It is pushed outward when the track is pulled past the start. |
endIcon | ReactNode | – | Icon after the track. It is pushed outward when the track is pulled past the end. |
name | string | – | Submits the value with a form through a hidden input. |
disabled | boolean | false | Blocks pointer and keyboard input and removes the thumb from the tab order. |
className | string | – | Extra class on the root. |
Keyboard interactions
| Keys | Action |
|---|---|
| ArrowRight / ArrowUp | Increases by one step. |
| ArrowLeft / ArrowDown | Decreases by one step. |
| Shift + Arrow / PageUp / PageDown | Moves by largeStep. |
| Home / End | Goes to min or max. At a limit, the track stretches toward the press and snaps back. |
Accessibility
- 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.
Motion
- 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.
Responsive behavior
- 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.
Performance
- 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
- 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.
Related
- Slider: Pick a value or a range on a track that follows your finger.
- Range histogram slider: A price range over a live histogram of the data, lighting the bars inside the range and settling on bar edges.
- Ruler slider: A tape of ticks that slides under a fixed needle, with momentum, snapping, and a rolling readout.
- Scrub input: A Figma-style number field: drag the label to scrub, or type values, units, and arithmetic.
- Number field: Enter a bounded number with clear increment controls.
Guidance for AI tools
Elastic slider: A slider that stretches like rubber past its ends, with a swaying value tag and detents the thumb clicks into. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.
Full library index: https://ui.xzero.co.uk/llms.txt