HextaUI

Textarea

Texto de várias linhas que cresce suavemente conforme o que você escreve, entre um número mínimo e máximo de linhas, com contadores, validação e um atalho de envio.

Grows with your text, then scrolls.

import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"

export function TextareaDemo() {
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel>Feedback</FieldLabel>
      <Textarea placeholder="What could we do better? Keep typing — the box grows with you." />
      <FieldDescription>Grows with your text, then scrolls.</FieldDescription>
    </Field>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/textarea.json

Adiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.

import { Textarea } from "@/components/ui/textarea"
<Textarea placeholder="Write something…" />

A caixa cresce com o texto, suavizando a cada nova linha em vez de saltar, de minRows até maxRows, e depois rola. A digitação nunca é atrasada pela animação.

Enviar com um atalho

submitOnShortcut envia o formulário com ⌘ + Enter ou Ctrl + Enter. Enter sozinho ainda inicia uma nova linha.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Kbd, KbdGroup } from "@/components/ui/kbd"
import { Textarea } from "@/components/ui/textarea"

export function TextareaSubmit() {
  const [comments, setComments] = React.useState<string[]>([])

  return (
    <form
      className="flex w-full max-w-sm flex-col gap-3"
      onSubmit={(event) => {
        event.preventDefault()
        const form = event.currentTarget
        const text = String(new FormData(form).get("comment") ?? "").trim()
        if (text) {
          setComments((list) => [...list, text])
          form.reset()
        }
      }}
    >
      {comments.length > 0 ? (
        <ul className="flex flex-col gap-1 text-sm">
          {comments.map((comment, index) => (
            <li
              key={index}
              className="rounded-md bg-muted px-3 py-2 whitespace-pre-wrap"
            >
              {comment}
            </li>
          ))}
        </ul>
      ) : null}
      <Textarea
        name="comment"
        aria-label="Comment"
        placeholder="Write a comment…"
        minRows={2}
        submitOnShortcut
      />
      <div className="flex items-center justify-between gap-3">
        <span className="flex items-center gap-1.5 text-xs text-muted-foreground">
          <KbdGroup>
            <Kbd keys="Mod+Enter" />
          </KbdGroup>
          to send
        </span>
        <Button type="submit" size="sm">
          Comment
        </Button>
      </div>
    </form>
  )
}

Contagem de caracteres

Com maxLength dentro de um Field, FieldCounter conta enquanto você digita e dá um aviso ao atingir o limite.

import { Field, FieldCounter, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"

export function TextareaCounter() {
  return (
    <Field className="w-full max-w-sm">
      <div className="flex items-baseline justify-between gap-3">
        <FieldLabel>Bio</FieldLabel>
        <FieldCounter />
      </div>
      <Textarea name="bio" maxLength={160} minRows={2} />
    </Field>
  )
}

Linhas

minRows e maxRows definem onde o crescimento começa e para.

import { Textarea } from "@/components/ui/textarea"

export function TextareaRows() {
  return (
    <div className="grid w-full max-w-md gap-4 sm:grid-cols-2">
      <Textarea
        aria-label="One to four rows"
        minRows={1}
        maxRows={4}
        placeholder="1–4 rows"
      />
      <Textarea
        aria-label="Five to fifteen rows"
        minRows={5}
        maxRows={15}
        placeholder="5–15 rows"
      />
    </div>
  )
}

Tamanho fixo

autoResize={false} mantém uma altura fixa com uma alça de redimensionamento vertical.

import { Textarea } from "@/components/ui/textarea"

export function TextareaFixed() {
  return (
    <Textarea
      aria-label="Notes"
      autoResize={false}
      minRows={4}
      placeholder="Fixed height. Drag the corner to resize."
      className="max-w-sm"
    />
  )
}

Estados

Desabilitado, somente leitura e inválido. Textareas inválidos tremem quando o envio de um formulário falha.

import { Textarea } from "@/components/ui/textarea"

export function TextareaStates() {
  return (
    <div className="grid w-full max-w-md gap-4 sm:grid-cols-3">
      <Textarea
        aria-label="Disabled"
        disabled
        placeholder="Disabled"
        minRows={2}
      />
      <Textarea
        aria-label="Read-only"
        readOnly
        defaultValue="Read-only text you can select but not change."
        minRows={2}
      />
      <Textarea
        aria-label="Invalid"
        aria-invalid
        placeholder="Invalid"
        minRows={2}
      />
    </div>
  )
}

Da direita para a esquerda

Texto, placeholder e cursor seguem a direção de leitura.

import { Textarea } from "@/components/ui/textarea"

export function TextareaRtl() {
  return (
    <div dir="rtl" className="w-full max-w-sm">
      <Textarea aria-label="رسالتك" placeholder="اكتب رسالتك هنا…" />
    </div>
  )
}
TeclaAção
EnterInicia uma nova linha.
⌘EnterEnvia o formulário, com submitOnShortcut. Ctrl + Enter no Windows e no Linux.
  • Rotule com FieldLabel ou aria-label.
  • Em telas touch o texto tem pelo menos 16px, para o iOS não dar zoom ao receber foco.
  • O atalho espera enquanto um método de entrada está compondo, então confirmar uma palavra em japonês ou chinês nunca envia a mensagem.
  • Com movimento reduzido, a caixa se redimensiona instantaneamente.
PropTipoPadrão
autoResizeCresce com o texto em vez de ter altura fixa.
booleantrue
minRows
number3
maxRows
number10
submitOnShortcutEnvia o formulário pai com ⌘/Ctrl + Enter.
booleanfalse
shakeTreme quando o envio do formulário o considera inválido.
booleantrue
AtributoDescrição
data-slot="textarea"O textarea.
data-autoresizePresente quando cresce com o texto.
--textarea-min-rows / --textarea-max-rowsDefinido a partir de minRows e maxRows.

Usado em blocos

Blocos que se baseiam em Textarea.