KDS
Forms

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".

Preview
Slider com label e valor numérico.
45%

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

PropTipoDefaultDescrição
valuenumber[]Controlado. Array (1 ou 2 thumbs).
defaultValuenumber[][min, max]Não controlado.
onValueChange(v: number[]) => voidDisparado em cada movimento.
onValueCommit(v: number[]) => voidDisparado ao soltar (drag end).
min / maxnumber0 / 100Limites.
stepnumber1Granularidade.
orientation'horizontal' | 'vertical''horizontal'Direção da trilha.
disabledbooleanfalseBloqueia thumbs.
invertedbooleanfalseInverte o sentido.
aria-labelstringObrigató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

Range
Dois thumbs — faixa de preço, intervalo.
Steps
step=10 — snap em granularidade grossa.

States

EstadoComportamento
DefaultThumb com hover ring 4px, focus-visible ring 4px.
disabledOpacidade 50%, ignora pointer/teclado.
data-orientation=verticalTrilha 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-nums no número exibido — evita saltos de largura.
  • Quando passos importam (faixas de salário em mil), use step que 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 permite lo > hi se você forçar via state externo.

Accessibility

ConcernComportamento
RolesCada 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×.
TouchHit area do thumb é 16px — combine com label clicável que mostra valor.
Labelaria-label ou Label vinculado obrigatório.
Reduced motiontransition-[color,box-shadow] respeita prefers-reduced-motion.
  • Input — para precisão numérica.
  • RadioGroup — para escolhas discretas.
  • Switch — para boolean simples.

On this page