Slider
Input numérico contínuo via thumb arrastável — volume, brilho, faixas.
Overview
Slider é um input contínuo: o usuário arrasta um thumb sobre uma
trilha. Single-thumb por padrão; passe um array de dois valores para
range (faixa de preço, intervalo de data).
A regra crítica: nunca renderize um Slider silencioso. Sempre
exiba o valor atual ao lado, num número tabular para evitar saltos
de largura. Slider é "aproximadamente onde", não "exatamente quanto" —
para precisão, prefira Input type="number".
Anatomy
<Slider value={[n]} | {[lo, hi]}>
├─ <SliderTrack>
│ └─ <SliderRange /> ← preenchimento bg-primary
└─ <SliderThumb /> (×N) ← uma por valor no array
</Slider>Usage
import { Slider } from "@kalvner/kds/forms/slider";
export function Volume({ value, onChange }) {
return (
<Slider
value={value}
onValueChange={onChange}
max={100}
step={1}
aria-label="Volume"
/>
);
}Props
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
value | number[] | — | Controlado. Array (1 ou 2 thumbs). |
defaultValue | number[] | [min, max] | Não controlado. |
onValueChange | (v: number[]) => void | — | Disparado em cada movimento. |
onValueCommit | (v: number[]) => void | — | Disparado ao soltar (drag end). |
min / max | number | 0 / 100 | Limites. |
step | number | 1 | Granularidade. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Direção da trilha. |
disabled | boolean | false | Bloqueia thumbs. |
inverted | boolean | false | Inverte o sentido. |
aria-label | string | — | Obrigatório se sem Label visível. |
Subcomponents
Slider é exportado como um único componente — track, range e
thumbs são internos, com data-slot para customização avançada.
Variants
States
| Estado | Comportamento |
|---|---|
| Default | Thumb com hover ring 4px, focus-visible ring 4px. |
disabled | Opacidade 50%, ignora pointer/teclado. |
data-orientation=vertical | Trilha vertical (mín. h-44). |
Composition
Em painéis de configuração, pareie Label + valor + Slider:
<div className="space-y-2">
<div className="flex items-baseline justify-between">
<Label htmlFor="brightness">Brilho</Label>
<span className="tabular-nums text-muted-foreground">{value[0]}%</span>
</div>
<Slider id="brightness" value={value} onValueChange={setValue} max={100} />
</div>Para faixa de preço com input direto, combine Slider (visual) + dois Input (preciso) — o slider é exploração, os inputs são ajuste fino.
When to use
- Volume, brilho, opacidade, zoom (controles aproximados).
- Faixas de filtro (preço, ano, distância).
- Ajustes contínuos onde 5 ou 10 unidades de diferença não importam.
When not to use
- Valores precisos que o usuário sabe digitar (idade, quantidade
exata) — use Input
type="number". - Escolhas discretas com poucos valores — use RadioGroup ou Select.
- Datas — use DatePicker (Phase 5) ou Calendar.
Best practices
- Mostre sempre o valor. Slider sem número é "jogue um dardo".
- Use
tabular-numsno número exibido — evita saltos de largura. - Quando passos importam (faixas de salário em mil), use
stepque faça sentido pro domínio, não 1. - Em mobile, aumente o área hit do thumb com
[&_[data-slot=slider-thumb]]:size-6. - Para range slider, valide
[lo, hi]antes de submeter — Radix permitelo > hise você forçar via state externo.
Accessibility
| Concern | Comportamento |
|---|---|
| Roles | Cada thumb é role="slider" com aria-valuenow, aria-valuemin, aria-valuemax. |
| Keyboard | ← → (↑ ↓) movem por step; Home / End vão ao mín / máx; PageUp / PageDown saltam 10×. |
| Touch | Hit area do thumb é 16px — combine com label clicável que mostra valor. |
| Label | aria-label ou Label vinculado obrigatório. |
| Reduced motion | transition-[color,box-shadow] respeita prefers-reduced-motion. |
Related
- Input — para precisão numérica.
- RadioGroup — para escolhas discretas.
- Switch — para boolean simples.