Dual Range Slider

An enhanced slider component that allows users to select a range between two values.

2575
tsx
import { DualRangeSlider } from '@/components/ui/dual-range-slider'
export function DualRangeSliderDemo() {
return (
<DualRangeSlider
defaultValue={[25, 75]}
showLabel
/>
)
}

Installation

CLI

bash
npx fivui add dual-range-slider

Manual

Copy and paste the following code into your project.

bash
npm install @radix-ui/react-slider
components/ui/dual-range-slider.tsx
"use client"
import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"
import { cn } from "@/lib/utils"
export interface DualRangeSliderProps
extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
formatLabel?: (value: number) => string
showLabel?: boolean
}
const DualRangeSlider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
DualRangeSliderProps
>(({
className,
formatLabel,
showLabel = true,
...props
}, ref) => {
const [values, setValues] = React.useState<number[]>(props.defaultValue as number[] || [25, 75])
const handleValueChange = (newValues: number[]) => {
setValues(newValues)
if (props.onValueChange) {
props.onValueChange(newValues)
}
}
const renderLabel = (value: number) => {
if (!showLabel) return null
return formatLabel ? formatLabel(value) : value.toString()
}
return (
<div className="relative w-full">
{showLabel && (
<div className="absolute -top-6 left-0 right-0 flex justify-between">
<span className="text-sm">{renderLabel(values[0])}</span>
<span className="text-sm">{renderLabel(values[1])}</span>
</div>
)}
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className
)}
onValueChange={handleValueChange}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb
className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
/>
<SliderPrimitive.Thumb
className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
/>
</SliderPrimitive.Root>
</div>
)
})
DualRangeSlider.displayName = "DualRangeSlider"
export { DualRangeSlider }

Examples

Default

2575
tsx
<DualRangeSlider defaultValue={[25, 75]} />

With Custom Label

$20$80
tsx
<DualRangeSlider
defaultValue={[20, 80]}
formatLabel={(value) => '$' + value}
/>

With Custom Range

$1000$5000
tsx
<DualRangeSlider
defaultValue={[1000, 5000]}
min={0}
max={10000}
step={100}
formatLabel={(value) => '$' + value}
/>

With Step

0100
tsx
<DualRangeSlider
defaultValue={[0, 100]}
step={10}
/>

Disabled

3070
tsx
<DualRangeSlider
defaultValue={[30, 70]}
disabled
/>

API Reference

DualRangeSlider

PropTypeDefaultDescription
defaultValuenumber[][25, 75]Initial values for the range
formatLabel(value: number) => string-Function to format the label values
showLabelbooleantrueWhether to show value labels
minnumber0Minimum value
maxnumber100Maximum value
stepnumber1Step increment value
disabledbooleanfalseWhether the slider is disabled

External Documentation