Textarea

A multiline field for notes, descriptions, and longer text.

import { Textarea } from "@sagui/ui";
Markdown
Loading demo

When to use

  • Free-form multi-line text like bios, comments, or feedback.
  • Fields with a live character count, which rolls its digits in the helper row.

When not to use

  • Use input for single-line values.
  • Use inline-edit with multiline for a description edited in place on a page.
  • Use tag-input when the text is really a list of short values.

Installation

Install the package and import the styles once. The installation guide covers the Tailwind setup.

$ npm install @sagui/ui

Usage

example.tsx
import { Textarea } from "@sagui/ui";

export function BioField() {
  const [bio, setBio] = useState("");
  return (
    <Textarea
      label="Bio"
      rows={4}
      value={bio}
      onChange={(event) => setBio(event.target.value)}
      description={`${280 - bio.length} characters left`}
    />
  );
}

Examples

Live count

Loading demo

With an error

Loading demo

API reference

Textarea

A labelled multi-line field with the same animated helper and error rows as Input.

Prop Type Default Description
label (required) string – Visible label, tied to the textarea with htmlFor.
description string – Helper copy under the field, linked through aria-describedby. Counts such as "120 characters" roll their digits.
error string – Error copy. Sets aria-invalid and renders in a role="alert" row.
...props TextareaHTMLAttributes<HTMLTextAreaElement> – Forwarded to the native textarea, including ref, rows, value, onChange, and maxLength.

Accessibility

  • Native textarea with a real label.
  • Description and error ids are merged into aria-describedby; errors set aria-invalid and use role="alert".
  • Animated copy is aria-hidden and mirrored in a visually hidden plain-text span.

Motion

  • Message rows open their height on a smooth spring; changed words rise in with a soft blur and counts roll only the digits that changed.
  • Reduced motion drops the roll, blur, and height spring for instant changes.

Responsive behavior

  • It fills its column with a 110px minimum height and a vertical resize handle; it does not auto-grow with content.
  • Hover border styles apply only on hover-capable fine pointers.

Performance

  • One ResizeObserver per field measures the helper row for its height spring; cheap for a form, but avoid hundreds in a table.
  • Recomputing a character count on each keystroke only re-renders the helper row words that changed.

Notes

  • Use for free-form, multi-line text. Use input for single lines and inline-edit for text edited in place on a page.
  • A live character count in description gets the rolling-digit treatment for free.

Also in inputs