# Textarea (w-textarea)

## Description

A multi-line text input with built-in form validation, auto-resizing, and styling support.

[Warp component reference](https://warp-ds.github.io/docs/components/text-area/frameworks/elements)

## Usage

A multi-line text input with built-in form validation, auto-resizing, and styling support.

The component automatically handles:

- Form integration
- Auto-resizing based on content and row constraints
- Built-in validation with customizable error messages
- Accessibility attributes and labeling

## Accessibility

If a visible label isn't specified, an `aria-label` must be provided to the text field for accessibility. If the field is labeled by a separate element, an `aria-labelledby` property must be provided using the `id` of the labeling element instead.

- Always provide a visible label (do not rely on `placeholder` alone).
- Do not rely on color alone for interaction feedback (e.g. error states).

## Examples

<elements-example>

```html
<w-textarea label="Description"></w-textarea>
```

</elements-example>

### Placeholder

Text hint that appears when the textarea is empty. Placeholder text should not be used as a substitute for a visible label.

<elements-example>

```html
<w-textarea
    label="Description"
    placeholder="Give as much detail as you can"
></w-textarea>
```

</elements-example>

### Height

You can control the height of the input field by setting either `minimum-rows` or `maximum-rows`

<elements-example>
    
```html
<w-textarea label="Description" minimum-rows="3"></w-textarea>
```

</elements-example>

With `maximum-rows` the content will start scrolling when it passes the limit. Note that the field stops being resizable. Setting `minimum-rows` is redundant when you set `maximum-rows`.

<elements-example>

```html
<w-textarea label="Description" maximum-rows="3" value="Line 1
Line 2
Line 3
Line 4
Line 5"></w-textarea>
```

</elements-example>

### Disabled

Consider using more informative alternatives before choosing to use disabled, as some users may not understand why an element is disabled.

<elements-example>

```html
<w-textarea
    label="Description" 
    value="This form field is ignored"
    disabled
></w-textarea>
```

</elements-example>

### Read only 

Makes the textarea content immutable while remaining focusable. The contents can still be copied.

<elements-example>

```html
<w-textarea
    label="Description"
    value="This content is read only"
    readonly
></w-textarea>
```

</elements-example>

## Styling API

This section documents the supported styling hooks for `<w-textarea>`.

Use these hooks to customize appearance without relying on internal structure or selectors.

Before changing the default styles, remember that doing so can result in less consistent experiences for users across the product. Prefer defaults.

- Prefer **component tokens** for size, spacing, and state styling.
- Use **parts** only for small, local tweaks.
- Avoid relying on internal class names or selectors.

### Parts

The textarea exposes a minimal set of parts that can be targeted for last‑mile layout or typography tweaks.

| Part | Targets | Typical use |
|---|---|---|
| `input` | native textarea element | minor typography or spacing tweaks |

Example:

```css
w-textarea::part(input) {
  letter-spacing: 0.5px;
}
```

Parts are intended as an **escape hatch**.
Prefer component tokens for anything state‑ or size‑related.


### Component tokens

Component tokens (`--w-c-input-*`) act as inputs to the textarea styling.
They can be set directly on the component or inherited from a parent container.

These tokens are **shared across textfield, textarea, and select** for consistent form styling.

```css
.form-section {
  --w-c-input-label-font-weight: 600;
  --w-c-input-help-text-color: var(--w-s-color-text);
}
```

Defaults are defined internally; setting a token is always optional.


#### Label tokens

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-label-color` | label text color | `--w-s-color-text` |
| `--w-c-input-label-font-size` | label font size | `--w-font-size-s` |
| `--w-c-input-label-line-height` | label line height | `--w-line-height-s` |
| `--w-c-input-label-font-weight` | label font weight | `700` |
| `--w-c-input-label-padding-bottom` | space below label | `0.4rem` |
| `--w-c-input-label-cursor` | cursor when hovering label | `pointer` |
| `--w-c-input-label-display` | label display mode | `block` |


#### Optional indicator tokens

When `optional` attribute is set, these tokens control the "(optional)" text styling:

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-optional-color` | optional text color | `--w-s-color-text-subtle` |
| `--w-c-input-optional-font-size` | optional text font size | `--w-font-size-s` |
| `--w-c-input-optional-line-height` | optional text line height | `--w-line-height-s` |
| `--w-c-input-optional-font-weight` | optional text font weight | `400` |
| `--w-c-input-optional-padding-left` | space before optional text | `0.8rem` |


#### Help text tokens

| Token | Purpose | Default |
|---|---|---|
| `--w-c-input-help-text-color` | help text color (normal state) | `--w-s-color-text-subtle` |
| `--w-c-input-help-text-color-invalid` | help text color when invalid | `--w-s-color-text-negative` |
| `--w-c-input-help-text-font-size` | help text font size | `--w-font-size-xs` |
| `--w-c-input-help-text-line-height` | help text line height | `--w-line-height-xs` |
| `--w-c-input-help-text-margin-top` | space above help text | `0.4rem` |
| `--w-c-input-help-text-display` | help text display mode | `block` |


## Implementation notes

### Shared token system

Textarea shares its label, optional indicator, and help text tokens with `w-textfield` and `w-select`. This ensures consistent form styling across all text input components.

## `<w-textarea>` API

Unless otherwise noted all properties are HTML attributes (as opposed to JavaScript object properties).

### Properties

| Name | Type | Default | Summary |
|-|-|-|-|
| checkValidity (JS only) | `checkValidity() => boolean` | `-` | Checks whether the textarea passes constraint validation |
| disabled | `boolean` | `false` | Makes the element not focusable and hides it from form submits |
| handler (JS only) | `handler(e: InputEvent) => void` | `-` | - |
| help-text | `string \| undefined` | `-` | Description shown below the input field |
| invalid | `boolean` | `false` | Mark the form field as invalid. |
| label | `string \| undefined` | `-` | Either a `label` or an `aria-label` must be provided. |
| maximum-rows | `number \| undefined` | `-` | Sets the maximum number of text rows before the content starts scrolling. |
| minimum-rows | `number \| undefined` | `-` | Sets the minimum number of text rows the textarea should display |
| name | `string \| undefined` | `-` | The [name](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#name) of the input field when submitting the form |
| optional | `boolean` | `false` | Show an icon behind the label indicating the field is optional |
| placeholder | `string \| undefined` | `-` | Shown in the textarea when it doesn't have a value |
| read-only | `boolean` | `false` | **Deprecated**: Use the native `readonly` attribute instead |
| readonly | `boolean` | `false` | Whether the input can be selected but not changed by the user |
| reportValidity (JS only) | `reportValidity() => boolean` | `-` | Checks validity and shows the browser's validation message if invalid |
| required | `boolean` | `false` | Whether user input is required on the input before form submission |
| resetFormControl (JS only) | `resetFormControl() => void` | `-` | - |
| setCustomValidity (JS only) | `setCustomValidity(message: string) => void` | `-` | Sets a custom validation message. Pass an empty string to clear. |
| validationMessage (JS only) | `string` | `-` | Returns the validation message if the textarea is invalid, otherwise an empty string |
| validity (JS only) | `ValidityState` | `-` | Returns the validity state of the textarea |
| value | `string \| undefined` | `-` | Lets you set the current value |

### Property Details

#### checkValidity (JS only)

Checks whether the textarea passes constraint validation

- Type: `checkValidity() => boolean`
- Default: `-`

#### disabled

Keep in mind that using disabled in its current form is an anti-pattern.

There will always be users who don't understand why an element is disabled, or users who can't even see that it is disabled because of poor lighting conditions or other reasons.

Please consider more informative alternatives before choosing to use disabled on an element.

- Type: `boolean`
- Default: `false`

#### handler (JS only)



- Type: `handler(e: InputEvent) => void`
- Default: `-`

#### help-text

Use in combination with `invalid` to show as a validation error message,
or on its own to show a help text.

- Type: `string | undefined`
- Default: `-`

#### invalid

Mark the form field as invalid.

Make sure to also set a `help-text` to help users fix the validation problem.

- Type: `boolean`
- Default: `false`

#### label

Either a `label` or an `aria-label` must be provided.

- Type: `string | undefined`
- Default: `-`

#### maximum-rows

Sets the maximum number of text rows before the content starts scrolling.

- Type: `number | undefined`
- Default: `-`

#### minimum-rows

Sets the minimum number of text rows the textarea should display

- Type: `number | undefined`
- Default: `-`

#### name

The [name](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#name) of the input field when submitting the form

- Type: `string | undefined`
- Default: `-`

#### optional

Show an icon behind the label indicating the field is optional

- Type: `boolean`
- Default: `false`

#### placeholder

Set a text that is shown in the textarea when it doesn't have a value.

Placeholder text should not be used as a substitute for labeling the element with a visible label.

- Type: `string | undefined`
- Default: `-`

#### read-only

**Deprecated**: Use the native `readonly` attribute instead



- Type: `boolean`
- Default: `false`

#### readonly

Whether the input can be selected but not changed by the user

- Type: `boolean`
- Default: `false`

#### reportValidity (JS only)

Checks validity and shows the browser's validation message if invalid

- Type: `reportValidity() => boolean`
- Default: `-`

#### required

Whether user input is required on the input before form submission

- Type: `boolean`
- Default: `false`

#### resetFormControl (JS only)



- Type: `resetFormControl() => void`
- Default: `-`

#### setCustomValidity (JS only)

Sets a custom validation message. Pass an empty string to clear.

- Type: `setCustomValidity(message: string) => void`
- Default: `-`

#### validationMessage (JS only)

Returns the validation message if the textarea is invalid, otherwise an empty string

- Type: `string`
- Default: `-`

#### validity (JS only)

Returns the validity state of the textarea

- Type: `ValidityState`
- Default: `-`

#### value

Lets you set the current value

- Type: `string | undefined`
- Default: `-`

