# Textarea

> A multi-line text field that grows with its text, with sizes and an error state.

- Name: `textarea`
- Status: beta
- Categories: forms
- File: the install writes `textarea.tsx` to your `ui` alias, `@/components/ui` by default.
- npm packages: `@base-ui/react`, `class-variance-authority`. The install adds them.
- Gallery: https://arbokui.com/components/textarea
- Registry item: https://arbokui.com/r/textarea.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the component:

   ```bash
   npx shadcn@latest add @arbokui/textarea
   ```

## Use it for

- Text that can run past one line: a comment, a bio, a bug report.
- Name it with a visible label. Give the textarea an id and point the label's htmlFor at it.
- Let it grow with the text. For a fixed height, add className='field-sizing-fixed' and set rows.
- Show errors with aria-invalid plus a message under it, linked with aria-describedby.

## Avoid it for

- One-line values like a name or an email address. Use an input.
- Text that needs bold, lists, or links. Use a rich text editor.
- Turning Enter into submit. People expect Enter to start a new line here.
- Using placeholder as the label. It disappears as soon as someone types.

## Props

- `size`: `"sm" | "md" | "lg"`. Default `"md"`. Minimum height, vertical padding, and text size. Horizontal padding stays aligned across sizes. Density scales them.
- `rows`: `number`. Visible lines. It only applies with className='field-sizing-fixed', because the default grows with the text.
- `disabled`: `boolean`. Default `false`. Blocks typing and removes the textarea from the tab order.
- `aria-invalid`: `boolean`. Shows the danger border. Set it when validation fails, and link the message with aria-describedby.
- `onValueChange`: `(value: string, details) => void`. Called with the new text on every change. Use it with value for a controlled textarea.
- `className`: `string`. Extra classes. Later classes win, so className='field-sizing-fixed' stops it from growing.

## Accessibility

- Renders a native \<textarea>, so Enter adds a new line and typing, selection, and autofill work as usual.
- It has no name on its own. Pair it with a \<label htmlFor>, or wrap it in a label.
- aria-invalid="true" tells screen readers the value is wrong. Put the reason in text next to it, not only in the red border.
- The border uses --input, which the theme tests hold to 3:1 against the page and cards.
- The focus ring uses --ring, which the theme tests hold to 3:1 against the page and cards.
- On touch screens the text is 16px, so iOS Safari does not zoom in when the textarea gets focus.

## Examples

### With a label

```tsx
<div className="grid gap-2">
  <label htmlFor="bio" className="text-sm font-medium">
    Bio
  </label>
  <Textarea id="bio" name="bio" placeholder="A few words about you" />
</div>
```

### Error message the textarea points to

```tsx
<div className="grid gap-2">
  <label htmlFor="reason" className="text-sm font-medium">
    Reason for the refund
  </label>
  <Textarea id="reason" aria-invalid aria-describedby="reason-error" />
  <p id="reason-error" className="text-sm text-destructive-soft-foreground">
    Tell us what went wrong so we can fix it.
  </p>
</div>
```

### Fixed height

```tsx
<Textarea aria-label="Release notes" className="field-sizing-fixed" rows={8} />
```
