Forms
Label
Rótulo acessível para controles de formulário — par obrigatório de Input, Select, Checkbox.
Overview
Label é o LabelPrimitive.Root do Radix com estilo do KDS. Ele faz
três coisas que um <label> HTML solto não faz com a mesma robustez:
- Vincula corretamente ao controle via
htmlFor+id, ou ao envolver o controle inline. - Captura cliques e dispara o foco/seleção do controle vinculado, mesmo quando há children intermediários.
- Dim automaticamente quando o controle vinculado está
disabled, via seletorespeer-disabledegroup-data-[disabled=true].
Em formulários, Label é obrigatório — ele é o que torna o campo acessível para leitores de tela, navegação por teclado e ferramentas de preenchimento automático.
Preview
Label canônico vinculado a um Input.
Anatomy
<Label htmlFor="control-id">
Texto do label
├─ Asterisco se obrigatório (com aria-label)
└─ Helper inline opcional (com peer ou children)
</Label>
<Input id="control-id" />A id do Input deve bater com o htmlFor do Label. react-hook-form
FormItemresolvem isso para você — geram um id único viaReact.useId()e propagam.
Usage
import { Label } from "@kalvner/kds/forms/label";
import { Input } from "@kalvner/kds/forms/input";
export function NameField() {
return (
<div className="grid gap-2">
<Label htmlFor="name">Nome</Label>
<Input id="name" />
</div>
);
}Default
Label + Input — o par mínimo.
Props
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
htmlFor | string | — | ID do controle vinculado. |
className | string | — | Classes Tailwind extras. |
...rest | React.ComponentProps<typeof LabelPrimitive.Root> | — | Tudo do Radix Label.Root. |
States
Required
Asterisco vermelho — anuncie como
obrigatório.Disabled
Dim automático via peer-disabled.
With helper text
Helper abaixo, em muted-foreground.
Usaremos para confirmar a conta.
Inline (Checkbox)
Label inline ao lado do controle.
Composition
Canonical form row
Label + Input + helper — a unidade mínima de qualquer form.
Como aparece no documento de identificação.
When to use
- Sempre que houver um Input, Textarea, Select, Checkbox, Switch ou Radio. Não há exceção razoável.
- Para agrupar visualmente um label de uma legenda de fieldset
(
<fieldset><legend>...) em grupos de controles relacionados.
When not to use
- Para títulos de seções dentro do formulário — use
<h2>/<h3>, não Label. - Para placeholder-only "labels" — sem Label visível, leitores de tela perdem contexto e o usuário esquece o campo ao começar a digitar.
- Para texto descritivo entre Label e Input — esse é o
FormDescription, não outro Label.
Best practices
- Label sempre acima do controle no web. Floating labels (label que vira placeholder quando vazio) podem ser estéticos mas reduzem affordance — um label estático ainda funciona melhor para a maioria.
- Asterisco com
aria-label="obrigatório". Sem o aria-label, o leitor de tela soletra "asterisco". Marque o asterisco como decorativo e atribua o significado correto. - Não duplique a label como placeholder. Placeholder é um exemplo
ou hint de formato (
voce@exemplo.com), não a repetição do label. - Cliques na label devem focar o controle. Não envolva texto arbitrário no Label esperando que o usuário descubra que ele é clicável — só o que é semanticamente "o label".
Accessibility
| Concern | Comportamento |
|---|---|
| Roles | <label> HTML nativo via Radix. Anuncia o controle vinculado. |
| Vinculação | htmlFor + id (preferido) ou wrap do controle como child. |
| Click target | Clicar no Label foca o controle. Para Checkbox/Radio, marca/desmarca. |
| Disabled | Dim automático via peer-disabled quando o controle vinculado está disabled. |
| Required | Asterisco precisa de aria-label="obrigatório". Combine com required no Input. |