← Components/Inputs & Forms

RangeSlider

rangeslider-1779378412658.tsx
'use client'
import { useState, useRef, useCallback } from 'react'

const MIN = 0
const MAX = 10000

export default function RangeSlider() {
  const [range, setRange] = useState([1000, 7500])
  const [active, setActive] = useState<number | null>(null)
  const trackRef = useRef<HTMLDivElement>(null)

  const getPercent = (val: number) => ((val - MIN) / (MAX - MIN)) * 100

  const handleMouseDown = useCallback((i: number) => (e: React.MouseEvent) => {
    e.preventDefault()
    setActive(i)
    const move = (me: MouseEvent) => {
      const track = trackRef.current!
      const rect = track.getBoundingClientRect()
      const percent = Math.max(0, Math.min(1, (me.clientX - rect.left) / rect.width))
      const value = Math.round(percent * (MAX - MIN) + MIN)
      setRange(r => {
        const next = [...r]
        next[i] = value
        if (i === 0 && value > next[1] - 500) return r
        if (i === 1 && value < next[0] + 500) return r
        return next
      })
    }
    const up = () => { setActive(null); document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', up) }
    document.addEventListener('mousemove', move)
    document.addEventListener('mouseup', up)
  }, [])

  const fmt = (n: number) => `€${n.toLocaleString()}`

  return (
    <div style={{ padding: 48, background: '#0A0A0A', display: 'flex', flexDirection: 'column', gap: 32 }}>
      <div>
        <div style={{ color: '#F5F5F0', fontWeight: 700, fontSize: 16, marginBottom: 4 }}>Price range</div>
        <div style={{ color: '#C9A84C', fontSize: 20, fontWeight: 800 }}>{fmt(range[0])} — {fmt(range[1])}</div>
      </div>

      <div style={{ position: 'relative', height: 40 }}>
        {/* Track */}
        <div ref={trackRef} style={{
          position: 'absolute', top: '50%', left: 0, right: 0,
          height: 4, background: 'rgba(255,255,255,0.1)', borderRadius: 4,
          transform: 'translateY(-50%)',
        }}>
          {/* Fill */}
          <div style={{
            position: 'absolute', height: '100%', background: '#C9A84C', borderRadius: 4,
            left: `${getPercent(range[0])}%`, right: `${100 - getPercent(range[1])}%`,
          }} />
        </div>

        {/* Handles */}
        {range.map((val, i) => (
          <div key={i}
            onMouseDown={handleMouseDown(i)}
            style={{
              position: 'absolute', top: '50%', transform: 'translate(-50%, -50%)',
              left: `${getPercent(val)}%`,
              width: 22, height: 22, borderRadius: '50%',
              background: '#C9A84C', border: '3px solid #0A0A0A',
              cursor: 'grab', boxShadow: active === i ? '0 0 0 4px rgba(201,168,76,0.3)' : 'none',
              transition: 'box-shadow 0.1s', zIndex: active === i ? 2 : 1,
              userSelect: 'none',
            }}
          />
        ))}
      </div>

      <div style={{ display: 'flex', justifyContent: 'space-between', color: '#555', fontSize: 12 }}>
        {[0, 2500, 5000, 7500, 10000].map(v => <span key={v}>{fmt(v)}</span>)}
      </div>

      <button style={{
        background: '#C9A84C', color: '#0A0A0A', border: 'none',
        padding: '12px 24px', borderRadius: 8, fontWeight: 700, cursor: 'pointer', fontSize: 14,
      }}>Apply filter</button>
    </div>
  )
}

Component info

CategoryInputs & Forms
Frameworkreact
TierFREE
Views0
Copies0

About

Dual-handle price range slider with live preview and formatted labels

More from Inputs & Forms

'use client';

import { useState, useEffect } from 'react';

interface Tag {
  id: number;
  name: string;
}

const TagInput = () => {
  const [tags, setTags] = useState<Tag[]>([]);
  const [inputValue, setInputValue] = useState('');
  const [suggest
TagInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface File {
  name: string;
  size: number;
  progress: number;
}

const FileUpload = () => {
  const [dragOver, setDragOver] = useState(false);
  const [files, setFiles] = useState<File[]
FileUpload
Inputs & Forms
import React, { useState } from 'react';

const OTPInput = () => {
  const [otp, setOtp] = useState(new Array(6).fill(''));
  const [activeIndex, setActiveIndex] = useState(0);

  const handleChange = (e, index) => {
    const value = e.target.value;
OTPInput
Inputs & Forms
'use client';

import React, { useState } from 'react';

interface RangeSliderProps {
  min: number;
  max: number;
  defaultValue: [number, number];
}

const RangeSlider: React.FC<RangeSliderProps> = ({ min, max, defaultValue }) => {
  const [minVal
RangeSlider
Inputs & Forms