Textarea

A multi-line text field built from slots and Context: pairs with a label and hint, grows to fit its content, and carries an optional character counter in its footer. Each part is a named export.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add textarea

Usage#

usage.tsxTSX
import {  TextareaRoot,  TextareaField,  TextareaLabel,} from "@/components/ui/textarea"export function Example() {  return (    <div className="flex flex-col gap-1.5">      <TextareaLabel htmlFor="message">Message</TextareaLabel>      <TextareaRoot>        <TextareaField id="message" placeholder="Write your message…" />      </TextareaRoot>    </div>  )}

Label & hint#

TextareaLabel sits above the control. Wire it with htmlFor pointing at the TextareaField’s id so clicking the label focuses the field. Pass required to append a destructive asterisk. TextareaHint renders helper text below; give it an id and reference it from the field’s aria-describedby. Both are the shared DS Label / Hint primitives.

Your notes go straight to the product team.

Auto-resize#

Pass autoResize to TextareaField and the field grows to fit its content as you type, with no inner scrollbar. It rides the native CSS field-sizing: content where the browser supports it (no JavaScript at all), and falls back to a scrollHeight measurement everywhere else, so it works in every browser. Growth stays in sync on paste, autofill, or a controlled reset. It pins the drag handle to none, since manual dragging would fight the content height.

No scrollbar: the field resizes to its content.

Character count addon#

For the common case, pass showCount to TextareaField and it renders the footer and counter for you, with no separate state and no extra parts. It tracks the field’s own length, so it works whether the field is controlled or uncontrolled. Add the native maxLength to show current / max and hard-cap the input.

0 / 180

Character counter (manual)#

For full control over the footer, compose it by hand. TextareaFooter is a slot inside the field’s border, ideal for a helper note on the left and a counter on the right. TextareaCount takes the current length and an optional max; it uses tabular-nums so the count never shifts the layout, and turns destructive once you go over. Pair it with hasError on the root to flush the whole field red.

Markdown supported0 / 180

Sizes#

Three sizes scale padding, text, and the minimum height: sm, md (the default), and lg. Set size on TextareaRoot; every part picks it up from context.

Resize#

The resize prop on TextareaRoot controls the drag handle: vertical (default), none, horizontal, or both. The handle stays clipped to the field’s rounded corner.

Error#

Pass hasError to TextareaRoot to switch the border and focus ring to the destructive color and set aria-invalid on the underlying textarea. Pass the same hasError to TextareaHint so the helper text doubles as the error message.

Add at least 20 characters.

Disabled#

FAQ#

`TextareaRoot` owns the bordered surface, size, resize behavior, and error state and shares them through Context, while `TextareaField` is the actual `textarea` element. Splitting them lets the footer and counter live inside the same border as the input.