<!-- Protocore Design System — Textarea -->
# Textarea

- **Category:** Inputs (`inputs`)
- **Slug:** `inputs/textarea`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { Textarea } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/inputs/textarea

> Sunken multi-line text control, with an opt-in auto-resize that grows the field to fit its content.

## When to use

Use **Textarea** whenever the input is more than a single line — commit messages, runbook notes, descriptions. Wrap it in a **Field** for the label and hint.

- Turn on `autoResize` for composer-style inputs where a scrollbar would feel cramped; leave it off for fixed-height slots in dense forms.
- For a single line of text, use **Input** instead — a one-row Textarea just invites accidental newlines.
- For structured or code content, consider a dedicated editor rather than a raw Textarea.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `autoResize` | `boolean` | no | — | Grow the field to fit its content instead of scrolling. Respects `rows` as the minimum. |
| `className` | `string` | no | — | — |
| `invalid` | `boolean` | no | — | Mark the field invalid — danger border plus `aria-invalid`. |
| `size` | `enum` | no | `md` | Control padding scale: `sm` · `md` (default) · `lg`. |
| `style` | `CSSProperties` | no | — | — |

## Examples

### Basics

A multi-line sibling of Input for longer free text — descriptions, notes, incident reports. `rows` sets the initial height; the field scrolls once content overflows.

```tsx
import { Field, Textarea } from "@protocore/pds";

export default function Basics() {
  // Wrap the control in a Field so it carries a real, associated label.
  return (
    <Field label="Incident description" style={{ maxWidth: 420 }}>
      <Textarea rows={4} placeholder="Describe the incident…" />
    </Field>
  );
}
```

### Auto-resize

Set `autoResize` to grow the field with its content instead of scrolling. `rows` becomes the minimum height. Works with both controlled and uncontrolled values.

```tsx
import { Textarea } from "@protocore/pds";
import { useState } from "react";

export default function AutoResize() {
  const [notes, setNotes] = useState(
    "Node eu-central-3 failed health checks at 14:02 UTC.\nRestarted; awaiting quorum.",
  );

  // autoResize grows the field to fit content; `rows` sets the minimum height.
  return (
    <Textarea
      aria-label="Incident notes"
      autoResize
      rows={2}
      value={notes}
      onChange={(e) => setNotes(e.target.value)}
      style={{ maxWidth: 420 }}
    />
  );
}
```

## Do & don't

**Do**

- Use Textarea for genuinely multi-line input.
- Enable autoResize for composers and note fields so content stays visible.
- Set a sensible rows minimum so the field doesn't start as a sliver.
- Wrap it in a Field for its label, hint, and error wiring.

**Don't**

- Don't use a one-row Textarea where an Input belongs.
- Don't combine autoResize with a fixed height style — they fight.
- Don't rely on the red border alone for invalid; add a Field error.
- Don't drop the label; a bare Textarea is unnamed to assistive tech.

## Accessibility

**Notes**

- Renders a native `<textarea>`; label it via Field or a wrapping `<label>`.
- `invalid` sets `aria-invalid`; pair it with Field's `error` text.
- `autoResize` is a visual convenience only — it doesn't change semantics or value.
- Respects the shared focus ring and accent focus border like every control.

## Related

`input`, `field`, `search-input`, `number-input`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
