Skip to content
Nizivo UI

Textarea

A multi-line native text area, at least 112 px tall, that grows with its content where the browser supports field-sizing and can be resized vertically. Inside a Field it is labelled, described and validated by the Field.

Tier: client

Import

import { Textarea } from '@nizivo/react/textarea';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/textarea.css';

Static or interactive

Client. It always ships its client leaf, which reads its Field through FieldScope, so a page with a Textarea also loads FieldScope. The server HTML is a native <textarea> that works before hydration. How to choose.

Height and padding

The box follows Figma's Textarea (7367:316): 12 px padding on every side and a minimum height of 112 px. Its height is the larger of that minimum and rows (3 by default), so up to four rows of Body/M sit at 112 px and rows={6} is taller. Where the browser supports field-sizing (Chrome and Edge 123 and later, not Firefox 129 or Safari 17.5) it also grows with its content, never below that height; elsewhere the user drags it taller. For a one-line box, such as a chat composer, lower the minimum with the --nz-textarea-min-block-size hook (0 leaves only rows).

.composer .nz-textarea {
  --nz-textarea-min-block-size: 0;
}

Text size on touch screens

Under a coarse pointer (a phone or a tablet), the text and the placeholder are 16 px (Body/L) instead of 14 px (Body/M), because iOS Safari zooms the page into a focused field whose text is smaller than 16 px. Each row is then Body/L's 25.6 px line instead of 21 px, so a tall rows grows more there (Mobile Safari 17.5 rounds each row down to 25 px); the 112 px minimum is the same. --nz-textarea-font replaces the font on every pointer, so a page that sets it also decides whether iOS zooms.

Examples

Basic

Inside a Field: the label, help text and native validation messages are wired for you.

Two or three sentences about the product.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Textarea } from '@nizivo/react/textarea';

export function TextareaExample(): JSX.Element {
  return (
    <Field
      label="Description"
      description="Two or three sentences about the product."
      required
      messages={{ valueMissing: 'Describe the product.' }}
    >
      <Textarea name="description" placeholder="Hand-thrown in Bristol, glazed in moss." />
    </Field>
  );
}

Rows

112 px at least (Figma 7367:316); rows above that sets the height, and the user can drag it taller. Where the browser has field-sizing, it also grows as the text does.

import type { JSX } from 'react';
import { Textarea } from '@nizivo/react/textarea';

export function TextareaRowsExample(): JSX.Element {
  return (
    <div style={{ display: 'grid', gap: 12, maxInlineSize: 420 }}>
      <Textarea aria-label="Short note" placeholder="The 112 px minimum" />
      <Textarea rows={6} aria-label="Long note" placeholder="Six rows" />
    </div>
  );
}

States

An error from the server, read-only and disabled.

Keep it under 200 characters.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Textarea } from '@nizivo/react/textarea';

export function TextareaStatesExample(): JSX.Element {
  return (
    <div style={{ display: 'grid', gap: 16, maxInlineSize: 420 }}>
      <Field label="Care instructions" error="Keep it under 200 characters.">
        <Textarea defaultValue="Dishwasher safe. Microwave safe. Not for the oven." />
      </Field>
      <Field label="Supplier note" readOnly>
        <Textarea rows={2} defaultValue="Packed in recycled card." />
      </Field>
      <Field label="Internal note" disabled>
        <Textarea rows={2} defaultValue="Archived." />
      </Field>
    </div>
  );
}

Props

Client component Renders data-slot="textarea" with the class nz-textarea. Props: TextareaProps. Source: src/textarea/textarea.client.tsx.

NameTypeDefaultDescription
invalidboolean–

An error message is presented for this textarea (§8.3). Inside a Field, the Field sets it; an explicit value here wins.

rowsnumber3

Visible lines of text. The height is the larger of these rows and 112 px (Figma 7367:316; the --nz-textarea-min-block-size hook lowers it), so up to 4 rows of Body/M sit at 112 px. Where the textarea grows with its content, that is also its minimum (1 to 10; a larger value keeps a 3-line minimum there).

  • Also takes every attribute of <textarea> except children; rows is redeclared above. (Omit<ComponentPropsWithRef<"textarea">, "children">)

Other exports

TextareaProps type

import type { TextareaProps } from '@nizivo/react/textarea'

The props of Textarea, listed above.

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
textarea
.nz-textarea
Textarea
root (no render); interactive, focus: self
none

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

HookDefaultRead as
--nz-textarea-bg
  • default: var(--nz-bg-surface)
  • default: var(--nz-bg-disabled)
  • data-readonly: var(--nz-bg-subtle)
  • background on .nz-textarea
--nz-textarea-border
  • default: var(--nz-border-control)
  • default: var(--nz-border-subtle)
  • data-invalid: var(--nz-border-critical)
  • border on .nz-textarea
--nz-textarea-fg--nz-text-primary
  • color on .nz-textarea
--nz-textarea-font
  • default: var(--nz-font-body-m)
  • default @media (pointer: coarse): var(--nz-font-body-l)
  • font on .nz-textarea
--nz-textarea-min-block-size7rem
  • --_nz-textarea-min on .nz-textarea
--nz-textarea-padding-block--nz-space-3
  • --_nz-textarea-padding-block on .nz-textarea
--nz-textarea-padding-inline--nz-space-3
  • padding-inline on .nz-textarea
--nz-textarea-placeholder-fg--nz-text-tertiary
  • color on .nz-textarea::placeholder
--nz-textarea-radius--nz-radius-md
  • border-radius on .nz-textarea

Layers: nz.components. Classes: .nz-textarea.

Tokens this stylesheet reads (20)

--nz-bg-disabled, --nz-bg-subtle, --nz-bg-surface, --nz-border-control, --nz-border-control-hover, --nz-border-critical, --nz-border-subtle, --nz-border-width-default, --nz-border-width-focus, --nz-duration-fast, --nz-easing-standard, --nz-focus-halo, --nz-focus-halo-critical, --nz-font-body-l, --nz-font-body-m, --nz-radius-md, --nz-space-3, --nz-text-disabled, --nz-text-primary, --nz-text-tertiary

Accessibility

These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:

  • textarea: draws the focus outline itself on keyboard focus.

Keyboard

KeysAction
TabMoves focus to the text area (Tab is not captured, so it also leaves it).
EnterStarts a new line; it never submits the form.

Source: a native <textarea> (textarea.client.tsx), which adds no key handling.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

  • Canonical: none
  • Ghost masters: none

On this page