ui icon indicating copy to clipboard operation
ui copied to clipboard

[feat]: Add ranges to Slider component

Open joaoGabriel55 opened this issue 1 year ago • 2 comments

Add Range support for the Slider component

Issue: #3932

Previews

Default

image

New York

image

joaoGabriel55 avatar Jun 13 '24 14:06 joaoGabriel55

Someone is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Jun 13 '24 14:06 vercel[bot]

Hi @shadcn, when you have time, could you look at these changes?

joaoGabriel55 avatar Aug 09 '24 12:08 joaoGabriel55

in case you need your own, just create this comp on your ui folder

'use client';

import * as SliderPrimitive from '@radix-ui/react-slider';
import * as React from 'react';

import { cn } from '@/lib/utils';

const RangeSlider = React.forwardRef<
  React.ElementRef<typeof SliderPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {
    onRangeChange?: (range: [number, number]) => void;
    initialRange?: [number, number];
  }
>(({ className, onRangeChange, initialRange = [0, 300], ...props }, ref) => {
  const [range, setRange] = React.useState<[number, number]>(initialRange);

  const handleValueChange = (newValue: number[]) => {
    const newRange: [number, number] = [newValue[0] ?? 0, newValue[1] ?? 0];
    setRange(newRange);
    onRangeChange?.(newRange);
  };

  return (
    <SliderPrimitive.Root
      ref={ref}
      className={cn(
        'relative flex w-full touch-none select-none items-center',
        className,
      )}
      min={initialRange[0]}
      max={initialRange[1]}
      step={30}
      value={range}
      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 size-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 size-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>
  );
});

RangeSlider.displayName = 'RangeSlider';

export { RangeSlider };

90PabloRomero avatar Sep 02 '24 22:09 90PabloRomero

I would use a more generic approach, to allow single or multiple thumbs in base of the value:

import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"

import { cn } from "@/lib/utils"

const Slider = React.forwardRef<
  React.ElementRef<typeof SliderPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, value, ...props }, ref) => (
  <SliderPrimitive.Root
    ref={ref}
    className={cn(
      "relative flex w-full touch-none select-none items-center",
      className
    )}
    minStepsBetweenThumbs={1}
    value={value}
    {...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>
    {value?.length ?
      (
        value.map((_v, i) =>
          <SliderPrimitive.Thumb key={i} 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>
))
Slider.displayName = SliderPrimitive.Root.displayName

export { Slider }

zalito12 avatar Oct 11 '24 19:10 zalito12

This PR has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this PR is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)

shadcn avatar Oct 11 '25 23:10 shadcn

Still believe this is relevant for 'Slider' section in order to be able to set between a range of 2 values

90PabloRomero avatar Oct 12 '25 14:10 90PabloRomero