Textarea
Preview appears after the next Storybook update.
<Textarea />When to use
Use it for
- Free text longer than one line: pull request summaries, release notes, review comments.
- showCount with maxLength when there is a hard limit.
- appearance="inline" only to edit existing text in place, where the text is the page: a paragraph, a list item or a card title in a docs editor. It keeps the surrounding font, size and line height and shows a field on hover and focus.
Not for
- A short single value: use Input.
- Structured content (lists of tokens, key-value pairs): use dedicated fields.
- appearance="inline" in a form, a dialog or a settings page: people scan forms for boxes, and an inline field there reads as plain text. Use the default field.
Do and don't
Every example is rendered with the real component, so it always matches what ships.
Size it for the expected answer
rows sets the starting height; autosize grows it, so short boxes do not hide long answers.
Inline only where the text already is
Swap the paragraph or list item for an inline Textarea holding the same text, so the page keeps its layout while it is edited. Name each one with aria-label.
Hiding the limit until it is hit
Show the count while typing so users can edit before the error.
Inline fields in a form
Without a box, an empty form field reads as finished text. Forms use the default field with a visible label.
Accessibility
- Native textarea through Base UI Field: label, description and error are wired for you.
- Focus shows a 2px signal edge; invalid sets aria-invalid and a danger edge with a text error.
- The visual counter is hidden from screen readers to avoid announcing every keystroke; maxLength is enforced natively.
- On touch screens the text is 17px so iOS does not zoom on focus.
- appearance="inline" is still a native, labelled textarea. Hover adds a fill and a hairline edge and focus the 2px DS ring, so the field never relies on color alone.
- The inline placeholder uses the muted text color, checked at 4.5:1 on the canvas, surfaces and the hover fill.
- Inline text inherits the page size, also on touch screens: keep the surrounding text at 16px or more so iOS does not zoom on focus.
Content guidelines
- Placeholder shows an example answer, not instructions.
- Use the hint for what makes a good answer.
From the code Generated from the component, not editable here.
Anatomy and tokens
Read from packages/react/src/components/Textarea/Textarea.module.css at build time. Every value is a token: open one to see its alias chain in both themes.
- Container
.wrapper - Native textarea
.textarea - Native textarea, placeholder
.textarea::placeholder - Native textarea, hover
@media (hover: hover) .textarea:hover:not([data-disabled], [data-invalid], [aria-invalid="true"], :focus) - Native textarea
.textarea:focus - Native textarea
.textarea[data-invalid], .textarea[aria-invalid="true"] - Native textarea
.textarea[data-invalid]:focus, .textarea[aria-invalid="true"]:focus - Native textarea, disabled
.textarea:disabled - Native textarea, disabled
.textarea:read-only:not(:disabled) - Character count
.count - Native textarea
@media (pointer: coarse) .textarea - Inline container, one space-2 past the text column on each side
.inlineWrapper - Inline appearance: page typography, height fits the content
.inline - Inline appearance: page typography, height fits the content, hover
@media (hover: hover) .inline:hover:not(:disabled, :read-only, :focus, [data-invalid], [aria-invalid="true"]) - Inline appearance: page typography, height fits the content, focus
.inline:focus-visible - Inline appearance: page typography, height fits the content
.inline[data-invalid], .inline[aria-invalid="true"] - Inline appearance: page typography, height fits the content, focus
.inline[data-invalid]:focus-visible, .inline[aria-invalid="true"]:focus-visible
Motion and interaction
Textarea animates on hover. Try it in the preview at the top.
| When | What changes | Duration | Easing |
|---|---|---|---|
| Hover | Border, background and shadow | motion.duration.instant75 ms | motion.easing.standardsettles in place |
With reduced motion turned on, every change happens at once.
From the code Generated from the component, not editable here.
Props
Parsed from the TypeScript types in packages/react/src/components/Textarea/Textarea.tsx, so this table cannot drift from the code. It also accepts every native <HTMLTextAreaElement> attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | none | Visible label. When set, the Textarea wraps itself in a Field. Leave unset inside a Field. |
hint | ReactNode | none | Helper text under the label. |
error | ReactNode | none | Error message. Marks the textarea invalid and announces the message. |
appearance | 'field' | 'inline' | 'field' | `field` (default) is the boxed form control. `inline` edits existing text in place: no border, no resize handle, the surrounding font, size and line height, and a height that always fits the content (`rows`, `maxRows` and `autosize` are ignored). Never use `inline` in a form. |
rows | number | 3 | Minimum visible lines. Default 3. Ignored by `appearance="inline"`, which always fits its content. |
maxRows | number | 12 | Grow with the content up to this many lines, then scroll. Default 12. Ignored by `appearance="inline"`. |
autosize | boolean | true | Grow with the content. Default true. When false the user can resize vertically. Ignored by `appearance="inline"`. |
showCount | boolean | false | Show "used / maxLength" under the field. Needs maxLength. |
hideLabel | boolean | none | Visually hide the Field label. Only with `label`. |
onValueChange | (value: string) => void | none | Called with the new string value on every change. |
Playground
Change the props and see the real Textarea update. Controls are generated from the TypeScript props; nothing here changes the system.
<Textarea label="Change summary" hint="Reviewers read this first. Say what changed and why." />Workbench
For contributors: every state with the accessibility panel, in the component workbench (Storybook). The stories double as visual test fixtures; the guidance on this page is the user documentation (open Textarea in Storybook).
Embed Storybook stories here (7)
Loads from https://bridge-storybook.floriangouloubi.com (set STORYBOOK_URL at build time). If Storybook is not running, the frames stay empty.
Default
WithCount
Invalid
Resizable
InAParagraph
InAList
AllStates
From the code Generated from the component, not editable here.
Changelog
- New
Textarea gets
appearance="inline"for editing existing text in place: no border, no resize handle, the surrounding font, size and line height, a height that fits the content (field-sizing: content, measured without moving the page where it is not supported), a fill and hairline on hover and the DS focus ring on focusv1.0.0, Nov 11, 2026
- Fix
Component specs count height and width as the content box (a bordered table cell is its height plus its border), the Figma build draws an empty sized slot at its padding instead of 100px, and stories reach every Figma variant: a disabled control on IconButton, Input, Select, Combobox and Textarea, and Figma variant stories for AccordionItem, MenuItem, MenuCheckboxItem, MenuSubmenu and TableEmpty
v1.0.0, Nov 11, 2026
- Fix
Component specs for Figma: inline custom properties set under a computed key or through a Base UI render element reach the CSS, a number held by a custom property and 1lh are read in calc() (a Textarea of 3 rows is 81px in Figma, as in code)
v1.0.0, Nov 11, 2026