Skip to main content
Gremorie

Textarea

Campo de texto multi-linha que cresce automaticamente via `field-sizing: content`, com os mesmos estados de focus e erro controlados por token do Input.

Visão geral

Textarea é um wrapper estilizado fino ao redor do <textarea> nativo. Ele usa field-sizing: content para que o campo cresça automaticamente conforme o usuário digita - sem malabarismo de rows, sem medição de altura via JS, sem dança de resize handle.

Os estados visuais combinam exatamente com o Input: border-input para o padrão, focus-visible:ring-ring/50 para focus, aria-invalid:border-destructive para erro. A altura mínima é min-h-16 para que textareas vazias sempre pareçam superfícies multi-linha.

Preview

'use client';import { Textarea } from '@gremorie/rx-forms';export function TextareaPreview() {  return (    <div className="max-w-md">      <Textarea placeholder="Write a description..." rows={4} />    </div>  );}

Anatomia

Textarea   único <textarea> estilizado, min-h-16, crescendo automaticamente via field-sizing: content

Instalação

bash npx gremorie@latest add rx-textarea
bash pnpm dlx gremorie@latest add rx-textarea
bash yarn dlx gremorie@latest add rx-textarea
bash bunx --bun gremorie@latest add rx-textarea

Uso

import { Label, Textarea } from "@gremorie/rx-forms";

export function Example() {
  return (
    <div className="grid gap-2">
      <Label htmlFor="bio">Bio</Label>
      <Textarea id="bio" placeholder="Tell us about yourself..." />
    </div>
  );
}

A edição Angular deste componente hoje é entregue a partir do código-fonte (veja o workbench para o comparativo lado a lado); a entrada de registry vem em seguida.

API

<Textarea>

PropTypeDefaultDescription
rowsnumber-Dica para as rows visíveis iniciais. Menos crítica aqui já que field-sizing: content sobrescreve o dimensionamento estático quando o usuário digita.
disabledbooleanfalseDesabilita a interação. Aplica cursor-not-allowed e opacity-50.
aria-invalidboolean-Quando true, troca a borda e o focus ring para o token destructive.

Estende todos os React.ComponentProps<"textarea">. Renderiza com data-slot="textarea".

Auto-grow via field-sizing: content é suportado no Chromium 123+ e no Firefox 128+. Para browsers mais antigos, a textarea ainda funciona mas não faz auto-resize; passe rows para definir uma altura estática razoável.

Composição

  1. <Textarea> é um primitive folha. Combine com <Label> para acessibilidade.
  2. Para compositores multilinha com toolbars ou buttons de submit, envolva com <InputGroup> e use <InputGroupTextarea> em vez disso, depois adicione um <InputGroupAddon align="block-end"> para o footer.
  3. Para react-hook-form, envolva com <FormField> + <FormControl> para conectar automaticamente as relações ARIA.

Variações

Com label

A textarea canônica estilo comentário. Combine-a com um <Label> vinculado via htmlFor e adicione uma description auxiliar quando o tamanho esperado importa.

'use client';import { Label, Textarea } from '@gremorie/rx-forms';export function TextareaWithLabelPreview() {  return (    <div className="grid w-full max-w-sm gap-2">      <Label htmlFor="message">Message</Label>      <Textarea id="message" placeholder="Type your message here." />    </div>  );}

Estado invalid

aria-invalid troca a superfície para destructive. Combine com aria-describedby apontando para o erro para que leitores de tela o anunciem.

Bio is required.

'use client';import { Label, Textarea } from '@gremorie/rx-forms';export function TextareaInvalidPreview() {  return (    <div className="grid w-full max-w-sm gap-2">      <Label htmlFor="bio">Bio</Label>      <Textarea        id="bio"        aria-invalid="true"        aria-describedby="bio-error"        defaultValue=""        placeholder="Tell us about yourself."      />      <p id="bio-error" className="text-sm text-destructive">        Bio is required.      </p>    </div>  );}

Disabled

disabled remove o campo da ordem de tabulação e do payload do formulário, reduz a opacidade e aplica cursor-not-allowed. Para conteúdo visível-mas-travado prefira readOnly (veja abaixo).

'use client';import { Textarea } from '@gremorie/rx-forms';export function TextareaDisabledPreview() {  return (    <div className="w-full max-w-sm">      <Textarea        disabled        placeholder="Disabled textarea"        defaultValue="This field is read only."      />    </div>  );}

Compositor de chat (com InputGroup)

Para superfícies de compositor com um button de envio embaixo, use InputGroup + InputGroupTextarea + align="block-end".

import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupTextarea,
} from '@gremorie/rx-forms';
import { Send } from 'lucide-react';

<InputGroup>
  <InputGroupTextarea placeholder="Write a message..." />
  <InputGroupAddon align="block-end">
    <InputGroupButton size="sm" variant="default" className="ml-auto">
      <Send />
      Send
    </InputGroupButton>
  </InputGroupAddon>
</InputGroup>;

Read-only

Use readOnly (não disabled) quando o conteúdo deve ser visível e selecionável mas não editável - ex. exibir SQL gerado ou uma nota salva.

<div className="grid gap-2">
  <Label htmlFor="generated-sql">Generated SQL</Label>
  <Textarea
    id="generated-sql"
    readOnly
    value="SELECT * FROM users WHERE created_at > '2026-01-01';"
  />
</div>

Acessibilidade

  • Labels: toda textarea precisa de um <Label> associado via htmlFor combinando com o id da textarea, ou de um aria-label explícito.
  • Focus: focus-visible ring de 3px controlado por focus-visible:ring-ring/50 - aparece apenas para usuários de teclado.
  • Validação: combine aria-invalid="true" com aria-describedby apontando para a mensagem de erro.
  • Disabled vs read-only: disabled remove o campo da ordem de tabulação e do payload do formulário. readOnly o mantém tabulável, selecionável e submetível - prefira-o para conteúdo somente de exibição.
  • Auto-grow: field-sizing: content mantém o cursor visível sem scroll manual quando a textarea excede o viewport.

Relacionados

  • Input - contraparte de linha única
  • Label - o companheiro canônico
  • Input Group - envolva com toolbar de footer para compositores
  • Form - conecta Textarea ao react-hook-form com helpers de ARIA

On this page