Slider
정해진 범위 안에서 값을 끌어서 고릅니다. 정확한 숫자보다 상대적인 크기가 중요한 값에 씁니다.
import { Slider } from 'neba';
<Slider label="볼륨" defaultValue={65} showValue />;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 높이와 타입 스케일 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 의미론적 색 역할. 임의 색상값은 받지 않습니다 |
| orientation공통 | 'horizontal' | 'vertical' | 'horizontal' | 트랙이 놓이는 방향. 세로는 길이를 직접 정해 주세요 |
| value | number | number[] | — | 현재 값. 배열이면 thumb이 값마다 하나씩 생깁니다 |
| defaultValue | number | number[] | — | 초기 값 |
| onValueChange | (value, details) => void | — | 끄는 동안 계속 호출됩니다 |
| onValueCommitted | (value, details) => void | — | 값이 확정될 때 한 번만. 네트워크 요청은 이쪽에 거세요 |
| min | number | 0 | 최솟값 |
| max | number | 100 | 최댓값 |
| step | number | 1 | 값이 움직이는 단위 |
| label | ReactNode | — | 트랙 위의 라벨 |
| description | ReactNode | — | 트랙 아래 보조 설명 |
| showValue | boolean | ((formatted, values) => ReactNode) | false | 라벨 옆에 현재 값을 보여 줍니다. 함수를 넘기면 표시 형식을 직접 정할 수 있습니다 |
| marks | boolean | readonly SliderMark[] | false | 트랙에 표시하는 지점. { value, label? } 배열이며, true면 step마다 눈금 하나입니다 |
| disabled | boolean | false | 사용 불가 |
| classNames | NebaSlots<'label' | 'control' | 'track' | 'indicator' | 'thumb' | 'description' | 'mark'> | — | 루트 뒤에 있는 각 파트의 class. 루트 자체는 className이 맡으므로 root 키는 없습니다 |
onValueChange는 끄는 동안 계속 호출되고, onValueCommitted는 값이 확정될 때 한 번만 호출됩니다. 네트워크 요청은 후자에 거세요.
정확한 숫자를 입력받아야 한다면 NumberField를 쓰세요.
예시
value 배열로 범위 지정
value에 숫자 배열을 주면 thumb이 그만큼 생기는 range slider가 됩니다. 별도의 prop은 없습니다.
import { useState } from 'react';
import { Slider } from 'neba';
export default function SliderRange() {
const [range, setRange] = useState<number[]>([200, 800]);
return (
<div className="w-full max-w-md">
<Slider
label="Price"
min={0}
max={1000}
step={50}
value={range}
onValueChange={(next) => setRange(next as number[])}
showValue={(formatted) => `$${formatted[0]} – $${formatted[1]}`}
/>
</div>
);
}min · max · step
step은 thumb이 멈추는 간격입니다. showValue는 현재 값을 라벨 옆에 표시합니다.
marks
marks는 트랙 위의 지점에 이름을 답니다. 개수 축의 1 / 100 / 250 / 500, 스타일 축의 양 끝 같은 것들입니다. { value, label? } 배열을 넘기고, label이 없는 mark는 눈금만 그려집니다.
값 없이 marks만 주면 step마다 눈금이 하나씩 생깁니다. step을 직접 정한 슬라이더에 어울리는 형태입니다. 기본값인 step={1}을 기본 범위에 쓰면 눈금이 백 개가 되므로, 그 경우에는 아무것도 그리지 않습니다.
이 줄은 스크린 리더에서 숨겨집니다. 값과 범위는 thumb이 이미 읽어 줍니다.
import { Slider } from 'neba';
const SIZES = [
{ value: 1, label: '1' },
{ value: 100, label: '100' },
{ value: 250, label: '250' },
{ value: 500, label: '500' }
];
const STYLES = [
{ value: 0, label: 'Realistic' },
{ value: 100, label: 'Abstract' }
];
export default function SliderMarks() {
return (
<div className="flex w-full max-w-sm flex-col gap-8">
<Slider label="Batch size" min={1} max={500} defaultValue={100} marks={SIZES} showValue />
<Slider label="Style" defaultValue={50} marks={STYLES} />
{/* `marks` on its own is a tick at every step, which is worth pairing
with a step you chose. */}
<Slider label="Strength" step={20} defaultValue={40} marks showValue />
</div>
);
}size
thumb은 트랙보다 크게 그려집니다. 실제로 손이 닿는 부분이므로 터치 대상 크기를 확보하기 위한 것입니다.
import { Slider } from 'neba';
const SIZES = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
export default function SliderSizes() {
return (
<div className="flex w-full max-w-md flex-col gap-6">
{SIZES.map((size) => (
<Slider key={size} size={size} label={size} defaultValue={50} />
))}
</div>
);
}orientation
vertical은 자기 길이를 갖지 않으므로 높이를 직접 지정하세요.
import { Slider } from 'neba';
const CHANNELS = [
{ label: 'Low', value: 70, color: 'primary' as const },
{ label: 'Mid', value: 45, color: 'info' as const },
{ label: 'High', value: 30, color: 'success' as const }
];
export default function SliderVertical() {
return (
<div className="flex items-end gap-8">
{CHANNELS.map((channel) => (
<div key={channel.label} className="flex flex-col items-center gap-2">
<Slider
orientation="vertical"
color={channel.color}
aria-label={channel.label}
defaultValue={channel.value}
/>
<span className="text-[0.75rem] text-[var(--neba-muted-fg)]">{channel.label}</span>
</div>
))}
</div>
);
}classNames
className은 루트(라벨과 스트립, 그 아래 한 줄을 담은 열)에 붙고, 그 안의 파트는 classNames로 잡습니다.
<Slider label="Volume" classNames={{ track: 'h-1', thumb: 'rounded-sm', mark: 'font-mono' }} />슬롯은 label, control, track, indicator, thumb, description, mark입니다. control은 press가 닿는 스트립 전체로, 그 안에 그려지는 track보다 두껍습니다.
접근성
- 각 thumb이 실제
<input type="range">이므로 방향키, Home/End, PageUp/PageDown이 그대로 동작합니다. label이 accessible name이 됩니다. 없으면aria-label을 주세요.showValue는<output>으로 렌더링되어 값이 바뀔 때 읽힙니다.- hover와 drag에서 thumb 크기는 변하지 않고 둘레에 ring이 그려집니다.