KDS
Forms

Checkbox

Controle de seleção binária ou indeterminada — usado em formulários a serem submetidos.

Overview

Checkbox é o Checkbox.Root do Radix com a indicator do KDS. Suporta três estados — unchecked, checked, indeterminate — via o prop checked que aceita boolean | "indeterminate". O ícone interno é o CheckIcon da lucide-react.

A diferença entre Checkbox e Switch é semântica, não visual: Checkbox é parte de uma form que será submetida (o usuário marca várias opções e depois clica Salvar). Switch tem efeito imediato (a configuração é persistida assim que o switch muda). Use o componente certo — confunde menos o usuário e simplifica o backend.

Preview
Checkbox com Label inline.

Anatomy

<Checkbox id="...">
  ├─ [data-slot="checkbox"]
  ├─ [data-state="checked" | "unchecked" | "indeterminate"]
  └─ <CheckIcon /> (renderizado quando checked ou indeterminate)
</Checkbox>

Usage

import { Checkbox } from "@kalvner/kds/forms/checkbox";
import { Label } from "@kalvner/kds/forms/label";

export function TermsField() {
  return (
    <div className="flex items-center gap-2">
      <Checkbox id="terms" />
      <Label htmlFor="terms">Aceito os termos</Label>
    </div>
  );
}

Props

PropTipoDefaultDescrição
checkedboolean | 'indeterminate'Controlado: estado atual.
defaultCheckedboolean | 'indeterminate'Não controlado: estado inicial.
onCheckedChange(c: boolean | 'indeterminate') => voidCallback de mudança.
disabledbooleanfalseBloqueia interação.
requiredbooleanfalseMarca como obrigatório.
aria-invalidbooleanAciona ring vermelho.
idstringVincula ao Label via htmlFor.

States

Unchecked
Estado padrão.
Checked
Background primary, ícone branco.
Indeterminate
Para árvores com filhos parcialmente marcados.
Disabled
Opacidade reduzida, sem pointer events.
Error
Ring vermelho via aria-invalid.
Aceite os termos para continuar.

Composition

Terms of service
Checkbox + texto com link inline.
Multi-select group
Múltipla seleção em um fieldset.
Notificações

When to use

  • Aceite de termos antes de submeter.
  • Múltipla seleção dentro de um formulário (notificações, permissões).
  • Linhas de tabela selecionáveis em ações em massa.
  • Estado tri-state (parcialmente selecionado) em árvores.

When not to use

  • Para alternar configuração de efeito imediato — use Switch.
  • Para escolher uma única opção entre várias — use RadioGroup.
  • Para ações de uma vez (ex: botão submeter), Checkbox não substitui Button.

Best practices

  • Tap target inclui o Label. Em mobile, o Checkbox em si é apenas 16px — clicar só nele é difícil. O <Label> aumenta a área hit porque clicar nele dispara o controle.
  • Marque obrigatório quando crítico. Asterisco vermelho no Label
    • required no Checkbox. Validação Zod com .refine(v => v === true).
  • Não use Checkbox para "ligar/desligar" feature flags. Esse é papel de Switch — tem efeito imediato.
  • Indeterminate é um estado, não uma ação. O usuário não clica para "ir pra indeterminate"; ela é setada programaticamente quando só alguns dos children estão marcados.

Accessibility

ConcernComportamento
RolesRadix expõe role="checkbox" + aria-checked (true, false, mixed).
KeyboardTab foca; Space alterna.
LabelVincule via htmlFor + id. Clicar no Label alterna o checkbox.
GroupPara grupos relacionados, envolva em <fieldset> + <legend>.
Erroaria-invalid aplica ring vermelho. Mensagem associada via aria-describedby.
Touch targetContainer clicável (Label + Checkbox) deve atingir 44×44 CSS px.
  • Switch — efeito imediato.
  • RadioGroup — escolha mutuamente exclusiva.
  • Form — wrappers de RHF + Zod.

On this page