Slider

Slider

사용자가 주어진 범위에서 값을 선택하는 입력 컴포넌트예요.

출처: 문서

본문

트랙과 썸을 드래그해 범위 내 값을 선택하는 슬라이더 컴포넌트예요. 여러 개의 썸(범위 슬라이더)을 지원하고, 키보드로 완전히 조작할 수 있으며 RTL 방향도 지원해요.

Features

  • 제어(controlled)/비제어(uncontrolled) 방식 모두 지원.
  • 여러 개의 썸 지원.
  • 썸 사이 최소 값 지원.
  • 트랙 터치/클릭으로 값 업데이트 지원.
  • 오른쪽에서 왼쪽(RTL) 방향 지원.
  • 완전한 키보드 내비게이션.

Anatomy

모든 파트를 임포트해 조립해요.

import { Slider } from "radix-ui";

export default () => (
  <Slider.Root>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
  </Slider.Root>
);

API Reference

Root

슬라이더의 모든 파트를 담아요. form 안에서 사용하면 이벤트 전파가 올바르게 되도록 썸마다 input이 렌더링돼요.

Prop Type Default
asChild boolean false
defaultValue number[] No default value
value number[] No default value
onValueChange function No default value
onValueCommit function No default value
name string No default value
disabled boolean false
orientation enum "horizontal"
dir enum No default value
inverted boolean false
min number 0
max number 100
step number 1
minStepsBetweenThumbs number 0
form string No default value
Data attribute Values
[data-disabled] Present when disabled
[data-orientation] "vertical" | "horizontal"

Track

Slider.Range를 담는 트랙이에요.

Prop Type Default
asChild boolean false
Data attribute Values
[data-disabled] Present when disabled
[data-orientation] "vertical" | "horizontal"

Range

범위(range) 파트예요. Slider.Track 안에 있어야 해요.

Prop Type Default
asChild boolean false
Data attribute Values
[data-disabled] Present when disabled
[data-orientation] "vertical" | "horizontal"

Thumb

드래그 가능한 썸이에요. 여러 썸을 렌더링할 수 있어요.

Prop Type Default
asChild boolean false
Data attribute Values
[data-disabled] Present when disabled
[data-orientation] "vertical" | "horizontal"

Examples

세로 방향

orientation prop으로 세로 슬라이더를 만들 수 있어요.

// index.jsx

import { Slider } from "radix-ui";

import "./styles.css";

export default () => (
  <Slider.Root className="SliderRoot" defaultValue={[50]} orientation="vertical">
    <Slider.Track className="SliderTrack">
      <Slider.Range className="SliderRange" />
    </Slider.Track>

    <Slider.Thumb className="SliderThumb" />
  </Slider.Root>
);
/* styles.css */

.SliderRoot {
  position: relative;
  display: flex;
  align-items: center;
}

.SliderRoot[data-orientation="vertical"] {
  flex-direction: column;
  width: 20px;
  height: 100px;
}

.SliderTrack {
  position: relative;
  flex-grow: 1;
  background-color: grey;
}

.SliderTrack[data-orientation="vertical"] {
  width: 3px;
}

.SliderRange {
  position: absolute;
  background-color: black;
}

.SliderRange[data-orientation="vertical"] {
  width: 100%;
}

.SliderThumb {
  display: block;
  width: 20px;
  height: 20px;
  background-color: black;
}

범위 만들기

여러 썸과 값을 추가해 범위 슬라이더를 만들어요.

import { Slider } from "radix-ui";

export default () => (
  <Slider.Root defaultValue={[25, 75]}>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />

    <Slider.Thumb />
  </Slider.Root>
);

스텝 크기 정의

step prop으로 증가 간격을 늘려요.

import { Slider } from "radix-ui";

export default () => (
  <Slider.Root defaultValue={[50]} step={10}>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
  </Slider.Root>
);

썸 겹침 방지

minStepsBetweenThumbs로 같은 값을 가진 썸을 피해요.

import { Slider } from "radix-ui";

export default () => (
  <Slider.Root defaultValue={[25, 75]} step={10} minStepsBetweenThumbs={1}>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />

    <Slider.Thumb />
  </Slider.Root>
);

숨겨진 input 분리하기

기본적으로 Slider.Thumb는 폼 제출을 위해 시각적으로 숨겨진 input을 렌더링해요. 그 input을 재구성하거나 이동하거나 제외하려면, 더 낮은 레벨의 파트들로 각 썸을 조립할 수 있어요.

중요: 이 파트들은 불안정하며 unstable_ 접두사가 붙어 있어서 API가 향후 릴리스에서 바뀔 수 있어요.

  • Slider.unstable_ThumbProvider는 썸 상태를 제공하고 제출 값의 선택적 name을 받아요.
  • Slider.unstable_ThumbTrigger는 드래그 가능한 썸 요소예요.
  • Slider.unstable_BubbleInput은 Slider.Thumb이 기본으로 렌더링하는 시각적으로 숨겨진 input이에요. 폼 제출이 필요 없으면 생략해요.
import { Slider } from "radix-ui";

export default () => (
  <Slider.Root defaultValue={[25, 75]}>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.unstable_ThumbProvider name="price[min]">
      <Slider.unstable_ThumbTrigger />

      <Slider.unstable_BubbleInput />
    </Slider.unstable_ThumbProvider>

    <Slider.unstable_ThumbProvider name="price[max]">
      <Slider.unstable_ThumbTrigger />

      <Slider.unstable_BubbleInput />
    </Slider.unstable_ThumbProvider>
  </Slider.Root>
);

Accessibility

Slider WAI-ARIA 디자인 패턴을 준수해요.

키보드 상호작용

Key Description
ArrowRight Increments/decrements by the step value depending on orientation.
ArrowLeft Increments/decrements by the step value depending on orientation.
ArrowUp Increases the value by the step amount.
ArrowDown Decreases the value by the step amount.
PageUp Increases the value by a larger step.
PageDown Decreases the value by a larger step.
Shift + ArrowUp Increases the value by a larger step.
Shift + ArrowDown Decreases the value by a larger step.
Home Sets the value to its minimum.
End Sets the value to its maximum.

Custom APIs

primitive 파트를 자신의 컴포넌트로 추상화해 나만의 API를 만들 수 있어요.

모든 파트 추상화

이 예제는 Slider의 모든 파트를 추상화해서 자동으로 닫히는 요소처럼 사용할 수 있게 해요.

사용법

import { Slider } from "./your-slider";

export default () => <Slider defaultValue={[25]} />;

구현

// your-slider.jsx

import { Slider as SliderPrimitive } from "radix-ui";

export const Slider = React.forwardRef((props, forwardedRef) => {
  const value = props.value || props.defaultValue;

  return (
    <SliderPrimitive.Slider {...props} ref={forwardedRef}>
      <SliderPrimitive.Track>
        <SliderPrimitive.Range />
      </SliderPrimitive.Track>

      {value.map((_, i) => (
        <SliderPrimitive.Thumb key={i} />
      ))}
    </SliderPrimitive.Slider>
  );
});

Caveats

마우스 이벤트가 발생하지 않아요

구현 중 마주친 제약 때문에 다음 예시는 기대대로 동작하지 않고 onMouseDown/onMouseUp 이벤트 핸들러가 발생하지 않아요:

<Slider.Root
  onMouseDown={() => console.log("onMouseDown")}
  onMouseUp={() => console.log("onMouseUp")}
>
  …
</Slider.Root>

포인터 이벤트를 사용할 것을 권장해요(예: onPointerDown, onPointerUp). 위 제약과 무관하게, 이 이벤트들은 모든 포인터 입력 타입(마우스·터치·펜 등)에서 발생하므로 크로스 플랫폼/디바이스 처리에 더 적합해요.

더 알아보기 (Learn more)

  • 여러 Slider.Thumb와 값을 넣으면 범위(range) 슬라이더가 돼요.
  • Slider.Thumb의 마우스 이벤트는 동작하지 않으므로 포인터 이벤트(onPointerDown 등)를 사용해야 해요.