Forms
Textarea
Campo de texto multi-linha com auto-resize via field-sizing CSS.
Overview
Textarea é a versão multi-linha do Input. Internamente usa
field-sizing: content (CSS moderno) — o campo cresce e diminui
conforme o conteúdo, sem JavaScript de medição. min-h-16 reserva
altura inicial e previne layout shift quando a página carrega
(ver [[ui/layout/cumulative-layout-shift]]).
Para entradas de uma linha, prefira Input. Para edição
rica (markdown, código, formatação), considere um editor dedicado —
Textarea trata só texto plano.
Preview
Textarea com auto-resize.
Anatomy
<Textarea
├─ [data-slot="textarea"]
├─ field-sizing: content (auto-grow)
└─ min-h-16 (altura inicial estável)
/>Usage
import { Textarea } from "@kalvner/kds/forms/textarea";
import { Label } from "@kalvner/kds/forms/label";
export function BioField() {
return (
<div className="grid gap-2">
<Label htmlFor="bio">Bio</Label>
<Textarea id="bio" placeholder="Conte um pouco sobre você" />
</div>
);
}Props
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
disabled | boolean | false | Bloqueia interação. |
readOnly | boolean | false | Permite seleção/cópia mas bloqueia edição. |
placeholder | string | — | Hint dentro do campo. |
rows | number | — | Linhas iniciais. Compete com min-h-16 — prefira não setar. |
aria-invalid | boolean | — | Aciona ring vermelho. |
...rest | React.ComponentProps<'textarea'> | — | Tudo de <textarea>. |
States
Default
Altura mínima preservada.
Disabled
Sem pointer events, opacidade reduzida.
Readonly
Selecionável, não editável.
Auto-resize
field-sizing: content cresce com o conteúdo.
Error
aria-invalid + mensagem abaixo.
Bio precisa ter pelo menos 20 caracteres.
Character count
Contador à direita, em texto pequeno.
51 / 280
Composition
Comment box
Caixa de comentário com helper, contador e submit.
Markdown habilitado0 / 500
When to use
- Mensagens de erro, comentários, descrições, biografias, qualquer texto livre de mais de uma linha.
- Conteúdo curto-a-médio — algumas frases, talvez um parágrafo.
- Onde Markdown puro é aceitável e edição rica não agrega.
When not to use
- Para edição rica (formatação, links, embeds), use um editor dedicado (TipTap, Slate, ProseMirror).
- Para entrada de uma linha, sempre
Input— Textarea de uma linha desperdiça espaço vertical e quebra layout. - Para listas estruturadas (tags, checklists), prefira componentes específicos.
Best practices
- Não set
rows. A altura mínima vem do CSS (min-h-16); o crescimento vem dofield-sizing. Setarrowsforça altura fixa e perde o benefício do auto-resize. - Contador de caracteres à direita, em
text-xs. Informativo, não competitivo com o input. Atualize só após primeiroonInputpara evitar flash de "0/500" inicial. - Helper e contador na mesma linha quando possível — cabem em
flex justify-between, otimizando espaço vertical. - Não anime height na transição idle → focused. Causa CLS. Use
border-colorebox-shadowem vez disso — [[ui/layout/cumulative-layout-shift]].
Accessibility
| Concern | Comportamento |
|---|---|
| Label | Sempre vincule via htmlFor + id. |
| Erro | aria-invalid + aria-describedby apontando para a mensagem. |
| Contador como descrição | Use aria-describedby apontando para o contador para que leitores de tela informem o limite. |
| Resize manual | Por padrão, <textarea> permite resize via canto inferior direito. field-sizing: content desabilita esse comportamento — ok para a maioria. |
| Touch target | Min-height 64px é confortável para mobile. |