docs / core / slider
Slider
one number, picked along a track by feel: a speed, an opacity, a blur radius. when the exact digits matter, ask with Input instead.
intensity · recedesrsc · client
provenance
authored in usvalayer
core / primitivesintensity
recedes · safe anywhere, including dense surfacescomposition
settings rows, filter panels, anywhere a value is tuned by feelpair label with showValue so the number stays visible while draggingnot a range picker. one thumb, one numbernot a substitute for a typed field when precision mattersa11y
role="slider" named by its label · arrow keys, Home and End move the thumb · focus ring on the thumbjest-axedependencies
@base-ui/react · class-variance-authoritylive demo · try it out
Opacity
customize
labeltext above the track
sizesm is for dense rows
minlower bound
maxupper bound
stepincrement per tick
defaultValuestarting position
suffixunit appended to the readout
showValuevalue readout on the right
disableddims and ignores input
usage
import { Slider } from "usva/primitives/slider";
<Slider
label="Opacity"
defaultValue={80}
step={5}
showValue
formatValue={(v) => `${v}%`}
/>props
| prop | type | default | notes |
|---|---|---|---|
| value | number | — | controlled value. |
| defaultValue | number | — | initial value when uncontrolled. |
| onValueChange | (value: number, event) => void | — | fires on every change, mid-drag and per key press. use onValueCommitted for release only. |
| min | number | 0 | lower bound. |
| max | number | 100 | upper bound. |
| step | number | 1 | increment per arrow key press and per drag tick. |
| disabled | boolean | false | dims to 50% and ignores pointer and keyboard. |
| label | ReactNode | — | label above the track. also names the slider for screen readers. |
| showValue | boolean | — | current value on the right of the label row. |
| formatValue | (value: number) => string | — | formats the readout. without it, Base UI's own formatting is used. |
| size | "sm" | "md" | "md" | track and thumb size. sm is for dense rows. |
get it
npx shadcn add https://usva.build/r/slider.jsonsource · components/ui/slider.tsxexactly what this command copies
"use client";
import { Slider as Base, type SliderRootProps } from "@base-ui/react/slider";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const trackVariants = cva(
"relative w-full select-none rounded-full border border-border bg-surface-2",
{
variants: {
size: {
sm: "h-1",
md: "h-1.5",
},
},
defaultVariants: { size: "md" },
},
);
const thumbVariants = cva(
cn(
"rounded-full border border-accent bg-gradient-accent shadow-raised outline-none transition-control duration-base ease-soft hover:glow-ring has-[:focus-visible]:ring-focus data-[dragging]:glow-ring",
"after:absolute after:content-['']",
),
{
variants: {
size: {
sm: "size-3.5 after:-inset-[5px]",
md: "size-4 after:-inset-1",
},
},
defaultVariants: { size: "md" },
},
);
const controlVariants = cva("flex w-full touch-none items-center py-1.5", {
variants: {
size: {
sm: "px-[7px]",
md: "px-2",
},
},
defaultVariants: { size: "md" },
});
export interface SliderProps
extends Omit<SliderRootProps<number>, "render" | "className">,
VariantProps<typeof trackVariants> {
className?: string;
label?: React.ReactNode;
showValue?: boolean;
formatValue?: (value: number) => string;
}
export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
(
{ className, size, label, showValue, formatValue, disabled, ...props },
ref,
) => (
<Base.Root
ref={ref}
disabled={disabled}
className={cn(
"flex w-full flex-col gap-2",
disabled && "cursor-not-allowed opacity-50",
className,
)}
{...props}
>
{label || showValue ? (
<div className="flex items-center justify-between gap-4">
{label ? (
<Base.Label className="text-sm text-ink select-none">
{label}
</Base.Label>
) : (
<span />
)}
{showValue ? (
<Base.Value className="font-mono text-xs tabular-nums text-muted">
{(formatted, values) =>
formatValue ? formatValue(values[0] ?? 0) : (formatted[0] ?? "")
}
</Base.Value>
) : null}
</div>
) : null}
<Base.Control className={controlVariants({ size })}>
<Base.Track className={trackVariants({ size })}>
<Base.Indicator className="rounded-full bg-accent bg-gradient-accent" />
<Base.Thumb className={thumbVariants({ size })} />
</Base.Track>
</Base.Control>
</Base.Root>
),
);
Slider.displayName = "Slider";