Range Slider
A flexible and intuitive slider component for selecting values from a range. Built on top of rc-slider, the RangeSlider component seamlessly integrates with RizzUI's design system, providing a consistent and accessible way to capture numeric input through visual interaction.
Features
- 🎚️ Range Selection - Single value or dual-handle range selection
- 📏 Multiple Sizes - Three size options (sm, md, lg) to match your design
- 🎯 Precise Control - Support for steps and marks for guided selection
- 📊 Customizable Marks - Add labels at specific points along the slider
- 🎨 Smooth Interactions - Smooth dragging with visual feedback
- ♿ Accessible - Built with accessibility best practices
- 🎯 Type Safe - Full TypeScript support
- 📝 Form Integration - Works seamlessly with form libraries
Installation
Before using the RangeSlider component, you'll need to install the required dependency:
Step 1
Install the rc-slider package.
- npm
- yarn
- pnpm
- bun
npm install rc-slider
yarn add rc-slider
pnpm add rc-slider
bun add rc-slider
Step 2
Create a range slider component, components/range-slider.tsx
import React from 'react';
import { tv, type VariantProps } from 'tailwind-variants';
import { cn } from 'rizzui/cn';
import Slider from 'rc-slider';
import type { SliderProps } from 'rc-slider';
import 'rc-slider/assets/index.css';
const rangeSlider = tv({
slots: {
container:
'[&>.rc-slider-rail]:!bg-gray-200 [&>.rc-slider-handle]:!opacity-100 [&>.rc-slider-handle-dragging]:!shadow-none [&>.rc-slider-handle-dragging]:!ring-4 [&>.rc-slider-track]:!bg-primary [&>.rc-slider-handle]:!border-primary-dark [&>.rc-slider-handle]:hover:!border-primary-dark [&>.rc-slider-handle-dragging]:!border-primary-dark [&>.rc-slider-handle-dragging]:!ring-primary/40 [&>.rc-slider-step>.rc-slider-dot-active]:!border-primary-dark',
},
variants: {
size: {
sm: {
container:
'[&>.rc-slider-rail]:!h-0.5 [&>.rc-slider-track]:!h-0.5 [&>.rc-slider-handle]:!h-3 [&>.rc-slider-handle]:!w-3 [&>.rc-slider-handle]:!border-[3px]',
},
md: {
container:
'[&>.rc-slider-rail]:!h-1 [&>.rc-slider-track]:!h-1 [&>.rc-slider-handle]:!h-4 [&>.rc-slider-handle]:!w-4 [&>.rc-slider-handle]:!border-4 [&>.rc-slider-handle]:!-mt-1.5',
},
lg: {
container:
'[&>.rc-slider-rail]:!h-2 [&>.rc-slider-track]:!h-2 [&>.rc-slider-handle]:!h-5 [&>.rc-slider-handle]:!w-5 [&>.rc-slider-handle]:!border-[5px] [&>.rc-slider-handle]:!-mt-1.5',
},
},
},
defaultVariants: {
size: 'md',
},
});
export interface RangeSliderProps extends SliderProps {
size?: VariantProps<typeof rangeSlider>['size'];
}
export default function RangeSlider({
size = 'md',
className,
...props
}: RangeSliderProps) {
const { container: containerClass } = rangeSlider({ size });
return <Slider className={cn(containerClass(), className)} {...props} />;
}
Usage
Basic Example
The simplest way to use the RangeSlider component with default settings:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider defaultValue={20} />;
}
Controlled Component
For controlled usage, manage the slider value with state:
import React from 'react';
import RangeSlider from '@components/range-slider';
export default function App() {
const [value, setValue] = React.useState(20);
return (
<RangeSlider
value={value}
onChange={(newValue) => setValue(newValue as number)}
/>
);
}
Sizes
Choose from three size options to match your design requirements:
import RangeSlider from '@components/range-slider';
export default function App() {
return (
<>
<RangeSlider size="sm" defaultValue={20} />
<RangeSlider defaultValue={25} />
<RangeSlider size="lg" defaultValue={30} />
</>
);
}
Range Mode
Enable dual-handle mode to select a range of values:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider defaultValue={[20, 60]} range />;
}
With Marks & Steps
Add marks and steps to guide users through specific values:
import RangeSlider from '@components/range-slider';
export default function App() {
return (
<RangeSlider
marks={{
0: '0',
20: '2000',
40: '4000',
60: '6000',
80: '8000',
100: '10000',
}}
step={20}
defaultValue={40}
/>
);
}
Range with Marks & Steps
Combine range mode with marks and steps for advanced range selection:
import RangeSlider from '@components/range-slider';
export default function App() {
return (
<RangeSlider
range
marks={{
0: '0',
20: '2000',
40: '4000',
60: '6000',
80: '8000',
100: '10000',
}}
step={20}
defaultValue={[20, 60]}
/>
);
}
With Range Counter
Create a custom range slider with input fields for min and max values:
import React from 'react';
import RangeSlider from '@components/range-slider';
import { cn } from 'rizzui/cn';
export default function App() {
const [state, setState] = React.useState({
min: 200,
max: 600,
});
function handleRangeChange(value: any) {
setState({
min: value[0],
max: value[1],
});
}
function handleMaxChange(max: number) {
setState({
...state,
max: max || state.min,
});
}
function handleMinChange(min: number) {
setState({
...state,
min: min || 0,
});
}
return (
<div>
<RangeSlider
range
min={0}
max={1000}
value={[state.min, state.max]}
onChange={(value: any) => handleRangeChange(value)}
className={cn('[&>.rc-slider-step]:hidden')}
/>
<div className="mt-5 flex items-center justify-between gap-5 text-sm font-bold">
<div className="overflow-hidden rounded-lg max-w-[200px] w-full border border-gray-200 py-2">
<p className="px-3 pt-1 text-gray-400">Min</p>
<input
type="number"
value={state.min}
onChange={(e) => handleMinChange(parseInt(e.target.value))}
className="w-full border-none !bg-gray-lightest p-3 pb-1 text-sm outline-none focus:shadow-none focus:ring-0"
min={0}
max={state.max}
readOnly
/>
</div>
<div className="overflow-hidden rounded-lg max-w-[200px] w-full border border-gray-200 py-2">
<p className="px-3 pt-1 text-gray-400">Max</p>
<input
type="number"
value={state.max}
onChange={(e) => handleMaxChange(parseInt(e.target.value))}
className="w-full border-none !bg-gray-lightest p-3 pb-1 text-sm outline-none focus:shadow-none focus:ring-0"
min={state.min}
readOnly
/>
</div>
</div>
</div>
);
}
Disabled State
Disable the slider to prevent user interaction:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider defaultValue={30} disabled />;
}
Advanced Usage
Vertical Slider
Display the slider vertically:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider vertical defaultValue={30} style={{ height: 200 }} />;
}
Custom Min/Max Values
Set custom minimum and maximum values:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider min={10} max={100} defaultValue={50} />;
}
Custom Step Size
Control the increment value:
import RangeSlider from '@components/range-slider';
export default function App() {
return <RangeSlider min={0} max={100} step={5} defaultValue={25} />;
}
Controlled Range
Manage range values with state:
import React from 'react';
import RangeSlider from '@components/range-slider';
export default function App() {
const [range, setRange] = React.useState([20, 80]);
return (
<RangeSlider
range
value={range}
onChange={(value) => setRange(value as number[])}
/>
);
}
API Reference
RangeSlider Props
| Prop | Type | Description | Default |
|---|---|---|---|
| size | "sm" | "md" | "lg" | Size of the slider component | "md" |
| value | number | number[] | Current slider value(s) (controlled) | undefined |
| defaultValue | number | number[] | Default slider value(s) (uncontrolled) | undefined |
| range | boolean | Enable dual-handle range mode | false |
| min | number | Minimum value | 0 |
| max | number | Maximum value | 100 |
| step | number | null | Step size for value changes | 1 |
| marks | Record<string | number, ReactNode | MarkObj> | Marks to display on the slider | undefined |
| disabled | boolean | Disable all slider interactions | false |
| vertical | boolean | Display slider vertically | false |
| reverse | boolean | Reverse the slider direction | false |
| allowCross | boolean | Allow handles to cross in range mode | true |
| pushable | number | boolean | Minimum distance between handles in range mode | false |
| draggableTrack | boolean | Allow dragging the track in range mode | false |
| onChange | (value: number | number[]) => void | Callback when value changes | undefined |
| onBeforeChange | (value: number | number[]) => void | Callback before value changes | undefined |
| onAfterChange | (value: number | number[]) => void | Callback after value changes | undefined |
| className | string | Additional CSS classes for the slider | undefined |
| style | CSSProperties | Inline styles for the slider | undefined |
Note: The RangeSlider component extends all props from rc-slider, allowing you to use features like
handleRender,trackStyle,handleStyle,railStyle, and more. Refer to the rc-slider documentation for a complete list of available props.
RangeSlider Sizes
type RangeSliderSizes = 'sm' | 'md' | 'lg';
- sm - Small size with compact handle (12px × 12px)
- md - Medium size with standard handle (16px × 16px) - default
- lg - Large size with larger handle (20px × 20px)
Best Practices
- Set appropriate min/max - Always define meaningful min and max values for your use case
- Use steps - Provide step values for discrete selections when appropriate
- Add marks - Use marks to guide users and show important value points
- Handle onChange - Use controlled components for form integration
- Consider range mode - Use range mode when users need to select a range of values
- Accessibility - The component includes built-in ARIA attributes for screen readers
- Mobile considerations - Ensure touch targets are large enough for mobile users
- Visual feedback - The component provides visual feedback during dragging