Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions components/slider/react/continuous-slider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# React Continuous Slider

A clean, accessible, and smooth **Continuous Slider** for React applications.
Ideal for selecting any values with in given range like volumes.

**Author:** [@SachinK.C.](https://github.com/sachinxmpl)

---

## ✨ Features

* **Smooth Control:** Allows continuous value selection (no steps).
* **Responsive & Accessible:** Keyboard and touch-friendly design.
* **Live Value Tooltip:** Displays the current value above the slider thumb.
* **Customizable:** Easily adjustable colors, size, and range.

---

## 🧾 Props

| Prop | Type | Default | Description |
| -------------- | ------------------------- | ------- | --------------------------- |
| `min` | `number` | `0` | Minimum slider value |
| `max` | `number` | `100` | Maximum slider value |
| `defaultValue` | `number` | `40` | Initial slider value |
| `onChange` | `(value: number) => void` | `null` | Callback when value changes |

---

## 🚀 Usage

```jsx
import ContinuousSlider from "./ContinuousSlider";

export default function Example() {
const handleValueChange = (val) => {
console.log("Slider value:", val);
};

return (
<div className="p-10">
<h2 className="text-lg font-semibold mb-4">Opacity Control</h2>
<ContinuousSlider min={0} max={100} defaultValue={50} onChange={handleValueChange} />
</div>
);
}
```
36 changes: 36 additions & 0 deletions components/slider/react/continuous-slider/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "continuous-slider",
"category": "slider",
"framework": "react",
"tags": ["slider", "continuous", "range", "smooth", "ui component", "react", "tailwind", "responsive"],
"author": "Sachin K.C.",
"license": "MIT",
"version": "1.0.0",
"preview": "A responsive, Tailwind CSS-based continuous range slider component for React.",
"props": [
{
"name": "min",
"type": "number",
"description": "The minimum selectable value of the slider.",
"default": 0
},
{
"name": "max",
"type": "number",
"description": "The maximum selectable value of the slider.",
"default": 100
},
{
"name": "defaultValue",
"type": "number",
"description": "The default value displayed when the slider is initialized.",
"default": 40
},
{
"name": "onChange",
"type": "(value: number) => void",
"description": "Callback triggered when the slider value changes.",
"default": null
}
]
}
82 changes: 82 additions & 0 deletions components/slider/react/continuous-slider/continuous_slider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";
import {useState } from "react";

const ContinuousSlider = ({
min = 0,
max = 100,
defaultValue = 40,
onChange = null,
}) => {
const [value, setValue] = useState(defaultValue);
const [hover, setHover] = useState(false);

const handleChange = (e) => {
const val = Number(e.target.value);
setValue(val);
if (onChange) onChange(val);
};

const percent = ((value - min) / (max - min)) * 100;
const tooltipPosition = Math.min(Math.max(percent, 0), 100);

return (
<div className="relative w-full max-w-[300px] h-[30px] mx-auto mt-12">
<input
type="range"
min={min}
max={max}
step="any"
value={value}
onChange={handleChange}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
aria-label="Continuous slider"
aria-valuenow={value}
className="w-full h-[6px] appearance-none rounded-md outline-none bg-gray-300"
style={{
background: `linear-gradient(to right, #0ea5e9 ${percent}%, #cdd6e0 ${percent}%)`,
}}
/>

<div
className={`absolute -top-7 px-2 py-[2px] text-xs rounded bg-gray-700 text-white transition-opacity duration-200 whitespace-nowrap ${
hover ? "opacity-100" : "opacity-0"
}`}
style={{
left: `${tooltipPosition}%`,
transform: "translateX(-50%)",
}}
>
{value.toFixed(2)}
</div>

<style jsx>{`
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 18px;
height: 18px;
border-radius: 9999px;
background: #0ea5e9;
cursor: pointer;
transition: transform 0.2s ease;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
}
input[type="range"]::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 9999px;
background: #0ea5e9;
cursor: pointer;
transition: transform 0.2s ease;
}
input[type="range"]::-moz-range-thumb:hover {
transform: scale(1.2);
}
`}</style>
</div>
);
};

export default ContinuousSlider;
Loading