# Textarea

> A multi-line text field with an optional live character counter and auto-growing height, built on a native textarea.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Forms
- Tags: textarea, text-field, form, validation, counter, auto-resize
- Docs: https://fancy-ui.rama.app/docs/components/textarea
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/textarea

## Import

```svelte
<script lang="ts">
  import { Textarea } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { Textarea } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `""` | Current value; bindable |
| `onValueChange` | `(value: string) => void` | — | Called with the new value on every input event |
| `placeholder` | `string` | — | Shown while the field is empty |
| `disabled` | `boolean` | `false` | Blocks focus and typing; excluded from form submission |
| `readonly` | `boolean` | `false` | Blocks typing but stays focusable and is still submitted, unlike disabled |
| `required` | `boolean` | `false` | Native required |
| `invalid` | `boolean` | `false` | Drives the error border and aria-invalid |
| `id` | `string` | — | Element id |
| `name` | `string` | — | Native name, read on form submission |
| `autocomplete` | `FullAutoFill` | — | Native autocomplete hint; the union from svelte/elements, not an arbitrary string |
| `label` | `string` | — | Accessible name — for a control with no visible Label next to it |
| `rows` | `number` | `3` | Visible height in text rows before anything grows it; also the no-JS height |
| `maxlength` | `number` | — | Native character ceiling; also the counter's denominator |
| `showCount` | `boolean` | `false` | Renders the live "n / max" counter under the field |
| `autoResize` | `boolean` | `false` | Grows to fit content instead of scrolling; disables manual resize |
| `class` | `string` | — | Additional CSS classes — applied to the textarea itself, not the wrapper |
| `ref` | `HTMLTextAreaElement \| null` | `null` | Bindable element reference |

## Examples

### Basic Usage

A single multi-line message field with a bound value.

```svelte
<script lang="ts">
	import { Textarea } from "fancy-ui-svelte";

	let message = $state("");
</script>

<div class="w-full max-w-sm">
	<Textarea bind:value={message} placeholder="A multi-line message…" label="Message" />
</div>
```

### With Counter

maxlength plus the live "n / max" counter.

```svelte
<script lang="ts">
	import { Textarea } from "fancy-ui-svelte";

	let message = $state("A multi-line message with resizing…");
</script>

<div class="w-full max-w-sm">
	<Textarea bind:value={message} maxlength={500} showCount label="Message" />
</div>
```

### Auto Resize

Grows with content instead of scrolling.

```svelte
<script lang="ts">
	import { Textarea } from "fancy-ui-svelte";

	let notes = $state("");
</script>

<div class="w-full max-w-sm">
	<Textarea bind:value={notes} autoResize rows={2} placeholder="Grows as you type…" label="Notes" />
</div>
```
