# Textarea

> Multiline text input with auto-resize, character count, and all Input features.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://www.sisyphosui.com/docs/components/textarea

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { Textarea } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { Textarea } from "@sisyphos-ui/react";

export const Bio = () => (
  <Textarea
    label="Bio"
    placeholder="Tell us a bit about yourself…"
    maxLength={140}
    showCharacterCount
  />
);
```

### Vue 3+

```vue
<script setup lang="ts">
import { Textarea } from "@sisyphos-ui/vue";
</script>

<template>
  <Textarea
    label="Bio"
    placeholder="Tell us a bit about yourself…"
    :maxLength="140"
    :showCharacterCount="true"
  />
</template>
```

### Angular 17+

```ts
import { Component } from "@angular/core";
import { Textarea } from "@sisyphos-ui/angular";

@Component({
  selector: "app-bio",
  standalone: true,
  imports: [Textarea],
  template: `
    <sui-textarea
      label="Bio"
      placeholder="Tell us a bit about yourself…"
      [maxLength]="140"
      [showCharacterCount]="true"
    />
  `,
})
export class BioComponent {}
```

## Examples

### Default

```tsx
import { useState } from "react";
import { Textarea } from "@sisyphos-ui/react";

export function Example() {
  const [value, setValue] = useState("");

  return (
    <div className="w-full max-w-sm">
      <Textarea
        label="Feedback"
        placeholder="Tell us what you think…"
        rows={4}
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </div>
  );
}
```

### Auto-resize

`autoResize` grows the textarea with content, clamped between `minRows` and `maxRows`.

```tsx
import { useState } from "react";
import { Textarea } from "@sisyphos-ui/react";

export function Example() {
  const [value, setValue] = useState("This textarea grows with content up to 8 rows.\nTry adding more lines…");

  return (
    <Textarea
      label="Message"
      autoResize
      minRows={2}
      maxRows={8}
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}
```

### With error

Pair `error` with `errorMessage` to show inline validation.

```tsx
import { Textarea } from "@sisyphos-ui/react";

export function Example() {
  return (
    <Textarea
      label="Bug report"
      defaultValue="App crashes"
      error
      errorMessage="Please describe the steps to reproduce (at least 40 characters)."
      rows={3}
    />
  );
}
```

### Character counter

`showCharacterCount` surfaces a `current / maxLength` counter in the corner.

```tsx
import { useState } from "react";
import { Textarea } from "@sisyphos-ui/react";

export function Example() {
  const [value, setValue] = useState("");

  return (
    <Textarea
      label="Bio"
      placeholder="A short description of yourself"
      maxLength={160}
      showCharacterCount
      rows={3}
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| variant | `"standard" \| "outlined" \| "underline"` | `"outlined"` | Visual treatment. |
| size | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Field size + typography scale. |
| radius | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"sm"` | Border radius scale. |
| label | `string` | — | Field label rendered above the textarea. |
| error | `boolean` | `false` | Marks the field as invalid for styling and ARIA. |
| errorMessage | `string` | — | Message shown below the field when `error` is true. |
| showCharacterCount | `boolean` | `false` | Show a `current / maxLength` counter (requires `maxLength`; hidden while an error message is shown). |
| autoResize | `boolean` | `false` | Grow the height with content, clamped between `minRows` and `maxRows`. |
| minRows | `number` | `3` | Minimum visible rows when `autoResize` is enabled. |
| maxRows | `number` | — | Maximum visible rows when `autoResize` is enabled; overflow scrolls past it. |
| resize | `"none" \| "vertical" \| "horizontal" \| "both"` | `"vertical"` | Native CSS resize handle direction. |
| fullWidth | `boolean` | `false` | Stretch the textarea to its container width. |

## Accessibility notes

- The label is wired through `htmlFor` / `id` (auto-generated when `id` is omitted).
- `aria-invalid` mirrors `error`; the error message is announced with `role="alert"`.
- Error message and character counter are linked to the field through `aria-describedby`.
- `disabled`, `readOnly`, and `required` are forwarded to the native `<textarea>` so form and AT semantics stay intact.

<!-- exports: { "Textarea": "@sisyphos-ui/react" } -->