컴포넌트

Slider

범위 안에서 숫자를 조절합니다.

설치

pnpm dlx ply-ui add slider

공통 설치 설정을 먼저 적용합니다.

사용법

min/max/step으로 범위와 이동 단위를 지정합니다.

Label과 Value는 설명과 현재 수치를 표시합니다. value/onValueChange로 상태를 연결합니다.

구성

구성 요소역할
Root값과 min, max, step을 관리합니다.
Label / Value이름과 현재 값을 표시합니다.
Control포인터 조작 영역입니다.
Track전체 범위를 표시합니다.
Indicator선택된 값 또는 구간을 표시합니다.
Thumb키보드와 포인터로 조작하는 손잡이입니다.

범위 선택

값 두 개와 Thumb 두 개로 구간을 선택합니다. 각 Thumb에 서로 다른 이름을 지정합니다.

비활성

Root.disabled는 모든 Thumb의 조작을 막습니다.

구현 코드

components/ui/slider.tsx
slider.tsx
"use client";

import type { ComponentProps } from "react";
import { Slider as Primitive } from "@base-ui/react/slider";
import { withClassName } from "../../lib/cx";
import "./slider.css";

// 동작과 접근성은 Base UI가 담당합니다. 이 파일은 스타일 연결만 담당합니다.
function SliderRoot({
  className,
  ...props
}: ComponentProps<typeof Primitive.Root>) {
  return (
    <Primitive.Root
      {...props}
      className={withClassName("rbx-slider", className)}
    />
  );
}

function SliderLabel({
  className,
  ...props
}: ComponentProps<typeof Primitive.Label>) {
  return (
    <Primitive.Label
      {...props}
      className={withClassName("rbx-label", className)}
    />
  );
}

function SliderValue({
  className,
  ...props
}: ComponentProps<typeof Primitive.Value>) {
  return (
    <Primitive.Value
      {...props}
      className={withClassName("rbx-description", className)}
    />
  );
}

function SliderControl({
  className,
  ...props
}: ComponentProps<typeof Primitive.Control>) {
  return (
    <Primitive.Control
      {...props}
      className={withClassName("rbx-slider-control", className)}
    />
  );
}

function SliderTrack({
  className,
  ...props
}: ComponentProps<typeof Primitive.Track>) {
  return (
    <Primitive.Track
      {...props}
      className={withClassName("rbx-slider-track", className)}
    />
  );
}

function SliderIndicator({
  className,
  ...props
}: ComponentProps<typeof Primitive.Indicator>) {
  return (
    <Primitive.Indicator
      {...props}
      className={withClassName("rbx-slider-indicator", className)}
    />
  );
}

function SliderThumb({
  className,
  ...props
}: ComponentProps<typeof Primitive.Thumb>) {
  return (
    <Primitive.Thumb
      {...props}
      className={withClassName("rbx-slider-thumb", className)}
    />
  );
}

// Root/Portal 등 스타일 없는 파트와 제네릭 API는 원본을 그대로 보존합니다.
export const Slider = {
  ...Primitive,
  Root: SliderRoot,
  Label: SliderLabel,
  Value: SliderValue,
  Control: SliderControl,
  Track: SliderTrack,
  Indicator: SliderIndicator,
  Thumb: SliderThumb,
};
components/ui/slider.css
slider.css
/* Slider: 공통 구조는 theme.css, 컴포넌트 전용 조정은 아래에 작성합니다. */
.rbx-slider {
  display: grid;
  gap: 8px;
  width: 100%;
}
.rbx-slider-control {
  display: flex;
  align-items: center;
  height: 28px;
  touch-action: none;
}
.rbx-slider-track {
  position: relative;
  height: 6px;
  border-radius: 99px;
  background: var(--rbx-color-shift-300);
  width: 100%;
}
.rbx-slider-indicator {
  position: absolute;
  border-radius: inherit;
  background: var(--rbx-color-system-emphasis);
}
.rbx-slider-thumb {
  width: 20px;
  height: 20px;
  border: 3px solid var(--rbx-color-system-emphasis);
  border-radius: 50%;
  background: var(--rbx-color-extended-white-100);
}
.rbx-slider[data-orientation="vertical"] .rbx-slider-control {
  width: 28px;
  height: 180px;
  justify-content: center;
}
.rbx-slider[data-orientation="vertical"] .rbx-slider-track {
  width: 6px;
  height: 100%;
}

목차