Installation
Registry — recommended
Copies the component into your configured shadcn UI directory and installs Motion.
npx shadcn@latest add https://suluu.site/r/slide-control.jsonnpm package
For centralized upgrades, install the optional ESM package and configure Tailwind source detection as shown below.
pnpm add suluu motionUsage
Give every slider a stable accessible name. Use defaultValue for local state, or pair value with onValueChange when your application owns the number.
import { SlideControl } from "@/components/ui/slide-control"
export function VolumeSetting() {
return (
<SlideControl
aria-label="Volume"
defaultValue={64}
onValueChange={(value) => saveVolume(value)}
/>
)
}// app/globals.css
@import "suluu/styles.css";
@source "../node_modules/suluu/dist";
// component.tsx
import { SlideControl } from "suluu/slide-control"
export function VolumeSetting() {
return <SlideControl aria-label="Volume" defaultValue={64} />
}Controlled state
const [volume, setVolume] = useState(64)
<SlideControl
aria-label="Volume"
onValueChange={setVolume}
value={volume}
/>Compose with CounterNumbers
SlideControl does not render a value label. Pair it with CounterNumbers when the number should roll as the thumb settles.
import { CounterNumbers } from "@/components/ui/counter-numbers"
import { SlideControl } from "@/components/ui/slide-control"
const [budget, setBudget] = useState(2400)
<div>
<CounterNumbers
formatOptions={{ currency: "USD", style: "currency", maximumFractionDigits: 0 }}
value={budget}
/>
<SlideControl
aria-label="Monthly budget"
max={8000}
min={400}
onValueChange={setBudget}
step={100}
value={budget}
/>
</div>In context
A budget cap stays readable as a rolling currency amount while the thumb settles.
Monthly budget
Caps the next billing period.
$2,400
Props
SlideControl accepts safe native div attributes, uses role="slider", and forwards its ref to the root element.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | — | Controlled committed value. |
| defaultValue | number | min | Initial uncontrolled value. |
| onValueChange | (value) => void | — | Runs when a drag, track press, or key press requests a new value. |
| min | number | 0 | Inclusive lower bound of the range. |
| max | number | 100 | Inclusive upper bound of the range. |
| step | number | 1 | Distance between committed values. Use 0 to disable snapping. |
| disabled | boolean | false | Disables every interaction. |
| motionIntensity | "subtle" | "default" | "expressive" | "default" | Controls the thumb spring, fill follow, and squash. |
| className | string | — | Class name applied to the slider. |
Theming
Override these variables in your light and dark theme scopes. The registry installs the defaults automatically.
--suluu-slide-trackUnfilled track surface.--suluu-slide-fillFilled track surface.--suluu-slide-thumbThumb surface.--suluu-slide-ringKeyboard focus ring.--suluu-slide-offsetColor behind the focus ring offset.--suluu-slide-track-shadowTrack inset depth.--suluu-slide-fill-shadowFill elevation.--suluu-slide-thumb-shadowThumb elevation.The root exposes data-dragging while the pointer is captured.
Accessibility
The control is a focusable slider with live aria-valuenow, aria-valuemin, and aria-valuemax. Arrow keys move by step, Page Up and Page Down move by a tenth of the range (at least one step), and Home and End jump to the ends. Disabled state leaves the tab order and blocks every input path.
With reduced motion, dragging still works but the thumb settle, fill follow, and squash become immediate.