# Text Area

A text area takes text that runs over several lines, such as a message, a description or feedback.

A text area takes text that runs over several lines: a comment, a bio, a bug report. For a single line, such as a name or an email address, use a [Text Field](/docs/text-field). For a chat composer that grows as people type and takes attachments, use a [Chatbar](/docs/chatbar).


## Usage

```tsx
import { Flex, Text, TextArea } from '@kushagradhawan/kookie-ui';

export function FeedbackField() {
  return (
    <Flex direction="column" gap="1">
      <Text as="label" htmlFor="feedback" size="2" weight="medium">
        What could we do better?
      </Text>
      <TextArea
        id="feedback"
        rows={5}
        maxLength={1000}
      />
    </Flex>
  );
}
```

## Best practices

**Give it a visible label.** Put the label above the text area and connect it with `htmlFor` or `aria-labelledby`. A placeholder disappears once someone starts typing.

**Set the height to the answer you expect.** Use `rows` so a short note gets two or three lines and a report gets more. People write less when the box looks small.

**Let people make it taller.** A text area resizes vertically by default, so people can drag the bottom edge when they write more than you planned for. Set `resize="none"` for a fixed layout, such as a dialog.

**Say what is wrong and how to fix it.** Set `error` and pass an `errorMessage` such as "Describe the problem in at least 20 characters". Show it after someone leaves the field or submits, not while they type.

**Use a Text Field for one line.** A text area tells people to write a lot. A name, a title or a search term belongs in a [Text Field](/docs/text-field).

## Variant

`variant` sets the look. The values match [Text Field](/docs/text-field), so both can sit in one form.

| Variant | Use it for |
| --- | --- |
| `raised` | Most forms. This is the default |
| `surface` | Fields on a plain background that need a clear edge |
| `soft` | Fields inside a card or a panel that already has a border |
| `outline` | Dense forms where a fill would feel heavy |
| `ghost` | Inline editing, such as a note that looks like text until focused |

## Size

`size` sets the text size and padding, and a minimum height of 28, 32, 40 or 48 pixels. Size 2 is the default. Use the same size as the text fields in the same form. `rows` sets how tall it actually is. `size` accepts a responsive object, such as `{ initial: '3', md: '2' }`.

## Resize

`resize` sets which way people can drag to resize. It is `vertical` unless you set it.

| Resize | Effect |
| --- | --- |
| `none` | Fixed size |
| `vertical` | Taller or shorter. The best choice for most forms |
| `horizontal` | Wider or narrower |
| `both` | Any direction |

`resize` accepts a responsive object, such as `{ initial: 'none', md: 'vertical' }`.

## Examples

### Character limit

`maxLength` stops typing at the limit. Show the count below so people know how much room is left.

```tsx
const [bio, setBio] = React.useState('');

<Flex direction="column" gap="1">
  <TextArea
    aria-label="Bio"
    value={bio}
    onChange={(event) => setBio(event.target.value)}
    maxLength={160}
  />
  <Text size="1" emphasis="medium">{bio.length} / 160</Text>
</Flex>
```

### Validation

`error` marks the text area as invalid and `errorMessage` shows below it, linked so a screen reader reads it with the field.

```tsx
<TextArea
  aria-label="Steps to reproduce"
  error
  errorMessage="Describe what you did before the error appeared"
/>
```

### Read-only text

`readOnly` keeps the text selectable and focusable but stops edits. Use it for something people copy, such as a generated key or a log. Use `disabled` only when the field doesn't apply right now.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'raised' \| 'surface' \| 'soft' \| 'outline' \| 'ghost'` | `'raised'` | The look |
| `size` | `'1' \| '2' \| '3' \| '4'`, responsive | `'2'` | Text size, padding and minimum height |
| `resize` | `'none' \| 'vertical' \| 'horizontal' \| 'both'`, responsive | `'vertical'` | Which way people can resize it |
| `color` | `AccentColor` | Theme accent | The colour of the focus ring |
| `radius` | `'none' \| 'small' \| 'medium' \| 'large' \| 'full'` | Theme radius | The corner |
| `value` | `string` | | The value, when you control it |
| `defaultValue` | `string` | | The starting value, when the field controls it |
| `error` | `boolean` | `false` | Marks the field as invalid |
| `errorMessage` | `string` | | Text shown below the field and linked to it |
| `required` | `boolean` | `false` | Must be filled before the form submits |

TextArea also accepts every attribute of the HTML `textarea` element, such as `rows`, `placeholder`, `maxLength`, `disabled`, `readOnly` and `onChange`.

## Accessibility

| Key | Action |
| --- | --- |
| Tab | Moves focus into the text area |
| Enter | Starts a new line |

- **Label:** The text area renders no label of its own. Connect a visible label with `htmlFor` and `id`, or pass `aria-label`.
- **Errors:** `error` sets `aria-invalid`. The `errorMessage` element is linked with `aria-describedby` and has `role="alert"`, so a screen reader reads it when it appears.
- **Focus:** The focus ring wraps the whole box and uses the field's colour.
- **High contrast:** In forced colors mode the box draws a real border, since the browser drops its shadows.
