I have a custom slider component in my React application where I’ve added two thumbs using the SliderPrimitive from @radix-ui/react-slider. The issue I’m facing is that whenever I add the onValueChange event, the thumbs cannot be moved, although I can see the changed values in the console. Without the onValueChange event, the thumbs move as expected.
Below is the code for my Slider component:
"use client"
import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"
import { cn } from "@/lib/utils"
const Slider = React.forwardRef(({ className, defaultValue = [0, 1000], max = 1000, step = 1, ...props }, ref) => {
const [value, setValue] = React.useState(defaultValue);
const handleChange = (newValue) => {
setValue(newValue);
};
const shouldDisplayRangeTogether = value[1] - value[0] < 100;
return (
<div className="relative w-full">
<SliderPrimitive.Root
ref={ref}
className={cn("relative flex w-full touch-none select-none items-center", className)}
value={value}
onValueChange={handleChange}
max={max}
step={step}
{...props}>
<SliderPrimitive.Track
className="relative h-0.5 w-full grow overflow-hidden rounded-full bg-gray-200 dark:bg-slate-800">
<SliderPrimitive.Range className="absolute h-full bg-dark-gray dark:bg-slate-50" />
</SliderPrimitive.Track>
{value.map((val, index) => (
<React.Fragment key={index}>
<SliderPrimitive.Thumb
className="block h-3 w-3 rounded-full border border-dark-gray bg-white duration-700 hover:bg-green ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-slate-950 focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 dark:border-slate-50 dark:bg-slate-950 dark:focus-visible:ring-slate-300"
/>
{!shouldDisplayRangeTogether && (
<div
className="absolute -top-8 w-10 text-center text-sm font-medium transform -translate-x-1/2"
style={{
left: `${(val / max) * 95}%`
}}
>
{props.currency}{val}
</div>
)}
</React.Fragment>
))}
</SliderPrimitive.Root>
{shouldDisplayRangeTogether && (
<div
className="absolute -top-8 left-1/2 transform -translate-x-1/2 text-sm font-semibold"
>
{props.currency}{value[0]} - {props.currency}{value[1]}
</div>
)}
</div>
);
});
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider }
Here’s how I’m using the Slider component in my Price component:
import React, { Fragment, useEffect, useState } from "react";
// Components
import { Slider } from "@/components/ui/slider";
const Price = () => {
const [prices, setPrices] = useState();
const [searchByPrice, setSearchByPrice] = useState();
async function getPrices() {
let response = await fetch("/api/filters/get-prices", {
method: "POST"
});
let data = await response.json();
setPrices(data.data);
}
useEffect(() => {
getPrices()
}, [])
const handleValueChange = (_prices) => {
setSearchByPrice(_prices);
};
return (
<Fragment>
<div className="bg-light-gray px-5 pt-5 pb-7 rounded-2xl">
<h6 className="text-base font-semibold mb-10">Price</h6>
{prices &&
<Slider
defaultValue={[prices[0].default_min_price, prices[0].default_max_price]}
max={prices[0].max_price}
step={1}
currency="₹"
onValueChange={handleValueChange}
/>
}
</div>
</Fragment>
);
};
export default Price;