# Textarea

A field for text on more than one line.

```tsx
import { Field, Textarea } from 'ferry-ui'

export default function TextareaHero() {
  return (
    <Field label="Description" optional hint="The description shows on the project page." className="w-full max-w-md">
      <Textarea placeholder="What is this project for?" />
    </Field>
  )
}
```

## Usage guidelines

- **Text on more than one line.** Use a textarea for a description, a message or a block of text that the user pastes.
- **One line is an input.** For one line of text, use [Input](/docs/components/input).
- **Not a code editor.** `mono` is for content that looks like code, such as JSON. To edit real code, use an editor component.
- **Give each textarea a label.** Use [Field](/docs/components/field), a [Label](/docs/components/label) or `aria-label`.

## Anatomy

Import the component. A textarea has one part.

```tsx title="Anatomy"

<Textarea />
```

## Examples

### Height

A textarea grows with its content. The minimum height is 80px.

Add a `max-h-*` class to set a maximum height. The textarea then scrolls.

```tsx
import { Field, Textarea } from 'ferry-ui'

const RELEASE_NOTES = [
  '- Invoices: the list loads faster.',
  '- Invoices: a filter by status.',
  '- Members: an owner can change a role from the list.',
  '- Members: an invitation stays valid for seven days.',
  '- API keys: each key shows the date of its last use.',
  '- Orders: the export contains the customer email.',
  '- Projects: the search finds archived projects.',
  '- Settings: a new page for the billing address.',
  '- Fixed: the total of an order with a discount.',
  '- Fixed: the date format in the exports.',
].join('\n')

export default function TextareaMaxHeight() {
  return (
    <Field label="Release notes" className="w-full max-w-md">
      <Textarea className="max-h-40" defaultValue={RELEASE_NOTES} />
    </Field>
  )
}
```

### Fixed height

Add the `field-sizing-fixed` class to stop the growth. Then set the height with `rows` or with an `h-*` class.

```tsx
import { Field, Textarea } from 'ferry-ui'

export default function TextareaFixed() {
  return (
    <Field label="Short note" className="w-full max-w-md">
      <Textarea className="field-sizing-fixed" rows={3} placeholder="Three rows, always" />
    </Field>
  )
}
```

### Monospace

Set `mono` for content that looks like code: JSON, a certificate or a list of keys.

```tsx
import { Field, Textarea } from 'ferry-ui'

const PAYLOAD = `{
  "event": "invoice.paid",
  "invoice": "INV-2041",
  "amount": 1280,
  "currency": "eur"
}`

export default function TextareaMono() {
  return (
    <Field label="Test payload" hint="The app sends this JSON to your endpoint." className="w-full max-w-md">
      <Textarea mono defaultValue={PAYLOAD} />
    </Field>
  )
}
```

### States

`disabled` stops all input. `aria-invalid` shows the error border. `Field` sets it when you pass `error`.

```tsx
import { Field, Textarea } from 'ferry-ui'

export default function TextareaStates() {
  return (
    <div className="flex w-full max-w-md flex-col gap-5">
      <Field label="Notes">
        <Textarea disabled defaultValue="You cannot edit an archived project." />
      </Field>
      <Field label="Reason" error="Enter 10 characters or more.">
        <Textarea defaultValue="Too short" />
      </Field>
    </div>
  )
}
```

### Controlled value

A textarea holds its value by default. Use `defaultValue` for the first value.

To control the value, pass `value` and `onChange`. This example counts the characters that the user can add.

```tsx
import * as React from 'react'
import { Field, Textarea } from 'ferry-ui'

const MAX_LENGTH = 280

export default function TextareaControlled() {
  const [message, setMessage] = React.useState('')

  return (
    <Field label="Feedback" hint={`${MAX_LENGTH - message.length} characters left`} className="w-full max-w-md">
      <Textarea
        placeholder="What must we change on the billing page?"
        maxLength={MAX_LENGTH}
        value={message}
        onChange={(event) => setMessage(event.target.value)}
      />
    </Field>
  )
}
```

## Accessibility

- A placeholder is not a label. Each textarea must have an accessible name.
- Show each error as text. Color alone is not sufficient.
- Link the hint and the error message to the textarea with `aria-describedby`. `Field` does this for you.

## API reference

`Textarea` also accepts each attribute of the `<textarea>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `mono` | `boolean` | `false` | Monospace face at 13px with relaxed line height. Use for code-like content (JSON, config snippets, certificates, lists of keys); keep prose in sans. |
