Slider
freeSlider selects a number or a range by dragging a thumb along a track.
Preview
Dark
import Slider from '@/components/ui/Slider';
export default function UsageDemo() {
return (
<div className="w-full max-w-sm">
<Slider defaultValue={60} />
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add SliderExamples
Range
Preview
Dark
import Slider from '@/components/ui/Slider';
export default function RangeDemo() {
return (
<div className="w-full max-w-sm">
<Slider.Range defaultValue={[20, 50]} />
</div>
);
}Disabled
Preview
Dark
import Slider from '@/components/ui/Slider';
export default function DisabledDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-8">
<Slider disabled defaultValue={60} />
<Slider.Range disabled defaultValue={[20, 50]} />
</div>
);
}Tooltips
Preview
Dark
Show on hover
Always visible
Custom content
import Slider from '@/components/ui/Slider';
export default function TooltipsDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-12">
<div className="flex flex-col gap-2">
<span className="text-sm font-medium">Show on hover</span>
<Slider showTooltipOnHover defaultValue={60} />
</div>
<div className="flex flex-col gap-2">
<span className="text-sm font-medium">Always visible</span>
<Slider alwaysShowTooltip defaultValue={60} />
</div>
<div className="flex flex-col gap-2">
<span className="text-sm font-medium">Custom content</span>
<Slider
showTooltipOnHover
defaultValue={60}
tooltip={(value) => `${value}%`}
/>
</div>
</div>
);
}Marks
Preview
Dark
import Slider from '@/components/ui/Slider';
const marks = [
{ value: 20, label: '$20k' },
{ value: 50, label: '$50k' },
{ value: 80, label: '$80k' },
];
export default function MarksDemo() {
return (
<div className="w-full max-w-sm">
<Slider defaultValue={40} marks={marks} />
</div>
);
}Step
Preview
Dark
import Slider from '@/components/ui/Slider';
const evenMarks = [
{ value: 0, label: '0°C' },
{ value: 25, label: '25°C' },
{ value: 50, label: '50°C' },
{ value: 75, label: '75°C' },
{ value: 100, label: '100°C' },
];
const unevenMarks = [
{ value: 0, label: '0°C' },
{ value: 26, label: '26°C' },
{ value: 37, label: '37°C' },
{ value: 100, label: '100°C' },
];
export default function StepDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-16">
<Slider
step={25}
defaultValue={25}
marks={evenMarks}
tooltip={(value) =>
evenMarks.find((mark) => mark.value === value)?.label
}
/>
<Slider
stepOnMarks
defaultValue={26}
marks={unevenMarks}
tooltip={(value) =>
unevenMarks.find((mark) => mark.value === value)?.label
}
/>
</div>
);
}Min And Max
Preview
Dark
import Slider from '@/components/ui/Slider';
export default function MinAndMaxDemo() {
return (
<div className="w-full max-w-sm">
<Slider showTooltipOnHover defaultValue={0} min={-20} max={20} />
</div>
);
}Custom Color
Preview
Dark
import Slider from '@/components/ui/Slider';
export default function CustomColorDemo() {
return (
<div className="w-full max-w-sm">
<Slider
defaultValue={70}
classNames={{
bar: 'bg-linear-to-r from-palette-blue via-palette-purple to-palette-rose',
thumb: 'border-palette-purple',
}}
/>
</div>
);
}Controlled
Preview
Dark
Value: 50
Range: 20 – 50
import { useState } from 'react';
import Slider from '@/components/ui/Slider';
export default function ControlledDemo() {
const [value, setValue] = useState(50);
const [range, setRange] = useState<[number, number]>([20, 50]);
return (
<div className="flex w-full max-w-sm flex-col gap-12">
<div className="flex flex-col gap-2">
<Slider value={value} onChange={setValue} />
<div className="text-sm text-muted-foreground">
Value: <span className="font-semibold text-foreground">{value}</span>
</div>
</div>
<div className="flex flex-col gap-2">
<Slider.Range value={range} onChange={setRange} />
<div className="text-sm text-muted-foreground">
Range:{' '}
<span className="font-semibold text-foreground">
{range[0]} – {range[1]}
</span>
</div>
</div>
</div>
);
}API
Slider selects a single value; Slider.Range selects a [start, end] pair with two thumbs. Both are uncontrolled with defaultValue or controlled with value and onChange, and both accept native div props.
Slider
| Prop | Description | Type | Default |
|---|---|---|---|
value | Current value in controlled mode. | number | - |
defaultValue | Initial value when uncontrolled. | number | 0 |
onChange | Fires with the new value while the value changes. | (value: number) => void | - |
onDraggingStop | Fires with the final value when a drag or key change ends. | (value: number) => void | - |
min | Lowest selectable value. | number | 0 |
max | Highest selectable value. | number | 100 |
step | Increment applied while dragging or using arrow keys. | number | 1 |
marks | Reference points rendered under the track. | SliderMark[] | [] |
stepOnMarks | Snap the thumb to mark values instead of stepping by step. | boolean | - |
precision | Decimal places kept in the reported value. | number | derived from step |
tooltip | Tooltip content, or a function of the current value. | SliderTooltip | identity |
showTooltipOnHover | Show the tooltip on hover, drag, and focus. | boolean | false |
alwaysShowTooltip | Keep the tooltip visible at all times. | boolean | false |
disabled | Prevent interaction and dim the track. | boolean | false |
thumbAriaLabel | Accessible label for the thumb. | string | - |
name | Name of the hidden input holding the value. | string | - |
inputProps | Props spread onto the hidden input. | ComponentPropsWithoutRef<'input'> | - |
classNames | Class names for individual slider parts. | SliderClassNames | {} |
className | Class names for the root element. | string | - |
ref | Ref forwarded to the root element. | Ref<HTMLDivElement> | - |
...nativeProps | Native props for the root div. | ComponentProps<'div'> | - |
Slider.Range
| Prop | Description | Type | Default |
|---|---|---|---|
value | Current range in controlled mode. | RangeSliderValue | - |
defaultValue | Initial range when uncontrolled. | RangeSliderValue | - |
onChange | Fires with the new range while it changes. | (value: RangeSliderValue) => void | - |
onDraggingStop | Fires with the final range when a drag or key change ends. | (value: RangeSliderValue) => void | - |
min | Lowest selectable value. | number | 0 |
max | Highest selectable value. | number | 100 |
minRange | Smallest allowed distance between the two thumbs. | number | 0 |
maxRange | Largest allowed distance between the two thumbs. | number | - |
step | Increment applied while dragging or using arrow keys. | number | 1 |
marks | Reference points rendered under the track. | RangeSliderMark[] | [] |
stepOnMarks | Snap thumbs to mark values instead of stepping by step. | boolean | - |
precision | Decimal places kept in the reported values. | number | derived from step |
tooltip | Tooltip content, or a function of a single thumb value. | SliderTooltip | identity |
showTooltipOnHover | Show tooltips on hover, drag, and focus. | boolean | false |
alwaysShowTooltip | Keep both tooltips visible at all times. | boolean | false |
disabled | Prevent interaction and dim the track. | boolean | false |
thumbArialLabelStart | Accessible label for the start thumb. | string | - |
thumbAriaLabelEnd | Accessible label for the end thumb. | string | - |
name | Base name for the hidden -from and -to inputs. | string | - |
inputProps | Props spread onto both hidden inputs. | ComponentPropsWithoutRef<'input'> | - |
classNames | Class names for individual slider parts. | RangeSliderClassNames | {} |
className | Class names for the root element. | string | - |
ref | Ref forwarded to the root element. | Ref<HTMLDivElement> | - |
Types
type RangeSliderValue = [number, number]
type SliderTooltip = ReactNode | ((value: number) => ReactNode)
type SliderMark = { value: number; label?: ReactNode }
type RangeSliderMark = { value: number; tooltip?: ReactNode }
type SliderClassNames = {
thumb?: string
bar?: string
mark?: string | ((isFilled: boolean) => string)
track?: string
}
type RangeSliderClassNames = {
thumb?: [string, string]
bar?: string
mark?: string
track?: string
}