Skip to content
WANCRAFT

A.34Buttons & Controls

Elastic Slider

A range slider whose track rubber-bands past either end and springs back on release.

NewReactMotionTailwindintermediate

Overview

Elastic Slider adds physical feedback to the most common control there is. Drag past the minimum or maximum and the track stretches from the opposite end, thinning as it goes, while the end icon is pushed outward; let go and a spring snaps it back with a little overshoot. The thumb swells while pressed and a value bubble follows it. Under the surface it is a proper WAI-ARIA slider with full keyboard support, pointer capture, stepping and a controlled or uncontrolled API.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/elastic-slider.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/elastic-slider.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/elastic-slider.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ElasticSlider } from "@/components/ui/elastic-slider";

export function ElasticSliderExample() {
  return (
    <ElasticSlider label="Volume" defaultValue={60} className="w-72" />
  );
}

03Props

PropTypeDefaultDescription
labelstring—Required. Visible label and accessible name (aria-labelledby).
value / defaultValuenumber— / 50Controlled value, or the initial value when uncontrolled.
onValueChange(value: number) => void—Called on every stepped change.
onValueCommit(value: number) => void—Called when a drag ends or a key changes the value.
min / max / stepnumber0 / 100 / 1Range and step granularity.
formatValue(value: number) => stringStringText for the bubble, the label row and aria-valuetext.
elasticitynumber28Maximum rubber-band stretch past either end, in px. 0 disables it.
spring{ stiffness: number; damping: number; mass: number }{ stiffness: 420, damping: 14, mass: 0.6 }Spring that snaps the band back on release.
bubble"always" | "active" | "off""active"When the value bubble is shown (active = dragging or keyboard focus).
hideLabelbooleanfalseVisually hide the label row (kept for screen readers).
accentstring"#FF7448"Fill, thumb core and focus ring colour.
startIcon / endIconReactNode—Decorative icons that are pushed outward by the stretch.
disabledbooleanfalseDisables pointer and keyboard input.
namestring—Renders a hidden input so the value submits with a form.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the root element.

04Features

  • 01Rubber-band stretch past either end with an exponential soft limit
  • 02Spring snap-back (configurable) with real overshoot
  • 03Thumb swells while pressed; a value bubble follows it
  • 04Stretch runs on motion values — only stepped value changes re-render
  • 05Controlled or uncontrolled, with step, custom formatting and form support
motion · springinput · draginput · pointerinput · keyboardinput · focus

05Accessibility

  • The thumb is a focusable role="slider" with aria-valuemin, aria-valuemax, aria-valuenow, aria-valuetext and aria-labelledby.
  • Arrow keys move by one step, Page Up / Page Down by a tenth of the range, Home / End jump to the ends.
  • Pressing past an end with the keyboard gives a small elastic bump instead of doing nothing silently.
  • Pointer capture keeps a drag alive outside the track; vertical page scrolling still works on touch.
  • Icons and the bubble are aria-hidden; the value is exposed through aria-valuetext. With prefers-reduced-motion there is no stretch, bump or press scale.