# Textarea

> Componentes / Formulário e ação · Estado: **Em andamento** — Implementado e utilizável, mas ainda sem a validação completa de acessibilidade.

Campo de texto de várias linhas — mensagem, justificativa, observação —, sobre o mesmo contrato visual do Input e do Select: borda de controle, foco em 2px e o vermelho só no erro.

- Função: Formulário e ação
- Também chamado de: área de texto, campo de mensagem, caixa de texto grande, textarea
- Mora em: `app/components/atoms/Textarea.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/Textarea](https://phorte-design-system.vercel.app/styleguide/peca/Textarea)
- Ficha no Storybook: [components-base-textarea](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-base-textarea--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/Textarea/0](https://phorte-design-system.vercel.app/previa/Textarea/0)
- Todas as peças: [https://phorte-design-system.vercel.app/llms.txt](https://phorte-design-system.vercel.app/llms.txt)

## Como usar no código

```tsx
import { Textarea } from '@/app/components/atoms/Textarea';

<Textarea />
```

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/Textarea/0)
2. [No formulário](https://phorte-design-system.vercel.app/previa/Textarea/1)
3. [Com contador](https://phorte-design-system.vercel.app/previa/Textarea/2)
4. [Com mínimo](https://phorte-design-system.vercel.app/previa/Textarea/3)
5. [Com mínimo e máximo](https://phorte-design-system.vercel.app/previa/Textarea/4)
6. [Acima do limite](https://phorte-design-system.vercel.app/previa/Textarea/5)
7. [Com proteção contra spam](https://phorte-design-system.vercel.app/previa/Textarea/6)
8. [Com erro](https://phorte-design-system.vercel.app/previa/Textarea/7)
9. [Desabilitado](https://phorte-design-system.vercel.app/previa/Textarea/8)
10. [Somente leitura](https://phorte-design-system.vercel.app/previa/Textarea/9)

Para resposta que pode passar de uma linha: a mensagem do "Fale conosco", a justificativa de um pedido de bolsa, uma observação.

### Quando não usar

Para dado de uma linha (nome, e-mail, CPF), use o Input. Para escolher entre opções conhecidas, o Select ou o Radio.

### Faça

- Use dentro de um FormField: o rótulo, a dica, o `contador` e o erro vêm dele.
- Dê `rows` pelo tamanho que se espera da resposta (quatro por padrão).
- Deixe a pessoa esticar na vertical (`redimensionar="vertical"`, o padrão).
- Peça um tamanho com o `contador` do FormField (E152): `{ maximo: 280 }`, `{ minimo: 50 }` ou os dois. Sem `atual`, ele conta sozinho. Valide no envio com `erroDeTamanho` (`app/lib/contagem-de-caracteres.ts`), que diz o mesmo número.
- Num formulário aberto ao público, ligue a proteção contra spam no formulário (E153): `useProtecaoContraSpam` dá o campo-isca e o tempo mínimo, e os sinais vão com o envio para o serviço decidir. Nada para a pessoa resolver.

### Evite

- Usar o `placeholder` como instrução: ele some ao digitar. A instrução vai na dica do FormField.
- Limitar com `maxLength`: o texto colado é cortado sem aviso. Use o `contador` com `maximo` — o texto continua entrando, o contador diz quanto passou e o envio recusa.
- Mostrar o mínimo como erro enquanto a pessoa digita: abaixo do mínimo o contador informa, em cinza; o erro é do envio.
- Proteger com CAPTCHA, teste de lógica ou bloqueio de colar: é barreira cognitiva (SC 3.3.8), e quem paga é a pessoa, não o robô.
- Redimensionar na horizontal: quebra o layout — o componente não oferece.

### Anatomia

1. **Caixa** — Borda `--border-interactive`, cantos do campo (`rounded-campo`), `px-4 py-3`, entrelinha folgada.
2. **Alça** — A do navegador, no canto de baixo, só na vertical.

### Estados

| Estado | O que muda |
| --- | --- |
| Padrão | Borda de controle de 1px. |
| Foco | Borda `--border-focus` de 2px (sombra interna), só no teclado e no clique — pelo CSS, como o Select. |
| Erro | `error` ou `aria-invalid` do FormField: borda `--destructive`, e `aria-invalid="true"`. |
| Desabilitado | A 50%, cursor proibido, fora do Tab. |
| Somente leitura | Borda tracejada e fundo `--muted`; continua no Tab e copiável. |
| Com contador | Embaixo do campo, pelo FormField: "N de 280 caracteres" (máximo), "faltam N para o mínimo de 50" (mínimo), ou os dois (E152). |
| Abaixo do mínimo | O contador em cinza, dizendo quanto falta. Não é erro: o campo não fica vermelho. |
| Acima do limite | O contador em vermelho, com o ícone e "N caracteres acima do limite". O texto continua entrando. |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Enter | Quebra a linha — não envia o formulário. Conferido no teste da ficha. |
| Digitando com contador | O contador muda a cada tecla; quem usa leitor de tela ouve quanto falta ou sobra 1s depois de parar de digitar, e não a cada tecla (padrão do GOV.UK). Conferido no teste da ficha. |
| Dentro do FormField | Recebe `id`, `aria-describedby` (dica, contador, erro) e `aria-invalid` do campo, sem repetir nada. |

### Relacionados

- [Input](https://phorte-design-system.vercel.app/styleguide/md/Input.md) — Dado de uma linha.
- [FormField](https://phorte-design-system.vercel.app/styleguide/md/FormField.md) — Rótulo, dica, contador e erro.
- [ContactForm](https://phorte-design-system.vercel.app/styleguide/md/ContactForm.md) — O formulário que tem a mensagem — migra para o Textarea na E73.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `redimensionar` | `'vertical' \| 'nenhum'` | `'vertical'` | não | Variante do `cva`. |
| `error` | `boolean` | — | não | Pinta a borda de erro **e** emite `aria-invalid`, como o `Input` e o `Select`. |

Aceita também: `React.TextareaHTMLAttributes<HTMLTextAreaElement>`.

### Medidas

| Parte | Valor | Classe |
| --- | --- | --- |
| Altura mínima | 96px, e quatro linhas por padrão | `min-h-24 · rows={4}` |
| Preenchimento | 16 × 12px | `px-espaco-4 py-espaco-3` |

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--muted` | #F4F6F9 | `bg-muted` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Leva o foco ao campo; o próximo Tab sai dele. Conferido no teste da ficha. |
| Enter | Quebra a linha (não envia o formulário) — conferido no teste da ficha. |

### Leitor de tela

- O nome vem do rótulo do FormField (ou do `aria-label`); o erro e a dica chegam por `aria-describedby` — conferido no teste da ficha.
- O erro é borda **e** `aria-invalid`, da mesma fonte: o vermelho nunca sozinho.
- O contador é parte da descrição do campo (lido ao chegar nele); o restante é anunciado numa região viva educada, só quando a pessoa para de digitar — conferido no teste da ficha.

### O que sustenta o estado

Usa os padrões: formulario. Falta ouvir com leitor de tela: formulario.

## Status e recursos

| Tipo | Recurso | Status |
| --- | --- | --- |
| Código | `app/components/atoms/Textarea.tsx` | Disponível |
| Ficha | https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-base-textarea--docs | Disponível |
| Teste de acessibilidade | axe em `npm run test` | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |

### Histórico

- `fdd10ff` 2026-09-29 — ESTADO: E109 concluida, roteiro final fechado; proximo o merge na main
- Histórico completo no GitHub: https://github.com/srbunnie/Pos-Phorte-Design-System/commits/main/app/components/atoms/Textarea.tsx
