Textarea

A textarea that grows as you type, with a character meter and a Cmd+Enter submit shortcut. For composers.

Textarea playground

Cmd+Enter to submit
47 / 280
sm drops into a dense form row; lg is the prominent composer - taller rhythm, larger type.

Install Textarea

1. New project? One command installs the package and wires everything - see Installation:

bash
pnpm dlx zyncat-ui init

2. Import the component - it loads its own stylesheet:

tsx
import { Textarea } from '@zyncat/ui/textarea';

Usage

tsx
import { Textarea } from '@zyncat/ui/textarea';
 
<Textarea label="Announcement" max={280} minRows={3} onSubmit={handleSubmit} hint="Cmd+Enter to submit" />

Compose Textarea in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.

Textarea props

Textarea

PropTypeDefaultDescription
...htmlAttributesHTMLAttributes—Standard <textarea> attributes (name, maxLength, aria-*, onKeyDown, ...) forwarded to the textarea.
valuestring''Controlled text value.
onChangeChangeEventHandler<HTMLTextAreaElement>—Change handler - fired on each edit with the textarea change event.
onSubmit(value: string) => void—Fired on ⌘/Ctrl+Enter with the current text.
maxnumber—Soft char limit: shows the meter + over-limit highlight. Does NOT truncate (use native maxLength for a hard stop).
minRowsnumber3Rows shown before auto-grow kicks in.
maxRowsnumber10Row cap - grows up to this, then the box scrolls.
warnAtnumber—Remaining-chars threshold that flips the meter amber. Default 20.
hintReactNode—Footer hint, left of the meter - e.g. a ⌘↵ affordance.
size'sm' | 'md' | 'lg''md'Field type and padding: `sm` for a dense form row, `lg` for a prominent composer.
classNamestring—Extra class(es) merged onto the field root.
styleCSSProperties—Inline styles merged onto the field root.
warningReactNode—Warning message - amber state. Loses to `error`; wins over `success`/`helper`.
successReactNode—Success message - green state. Loses to `error`/`warning`; wins over `helper`.
idstring—Field id, ties the label to the control.
requiredboolean—Mark the control required - reaches the native element and shows a danger `*` after the label.
optionalboolean—Show a muted "(optional)" after the label.
labelReactNode—Label text (sentence case).
helperReactNode—Neutral helper text - shown when there's no validation message.
errorReactNode—Error message - sets the error state (border + icon + colour). Wins over warning/success/helper.

Frequently asked questions

Yes - it starts at minRows (default 3) and grows on every keystroke up to maxRows (default 10), then switches to an internal scrollbar. A ResizeObserver also re-measures it whenever the field's own width changes, such as a sidebar collapsing.

Pass onSubmit - it fires with the current text on Cmd+Enter or Ctrl+Enter, and the keystroke is prevented from inserting a newline. Pair it with hint="Cmd+Enter to submit" to surface the shortcut in the footer.

No - max is a soft limit. Past it, the extra characters get a danger-tinted highlight and underline right in the text and the ring meter turns red, but nothing is truncated; for a hard stop, forward the native maxLength through htmlProps.

It turns amber once warnAt characters remain (default 20), and switches to the danger color once you're past max. The count itself also flips from 'count / max' to a plain countdown of characters left as soon as you enter the warning zone.

Set in Geist & Newsreader — animated by the house engineZyncat UI · Rev 0.11 · MIT · Built by Tabsir Ahammed · Source on GitHub