Textarea
A multi-line input for entering longer text. Supports clear editing and flexible sizing for different content needs.
<script setup lang="ts">
import { ref } from 'vue'
import { Textarea } from 'frappe-ui'
const value = ref('')
</script>
<template>
<Textarea v-model="value" placeholder="Write something..." />
</template>Variants
<script setup lang="ts">
import { Textarea } from 'frappe-ui'
</script>
<template>
<div class="flex flex-col gap-4 w-full max-w-sm">
<Textarea variant="subtle" label="Subtle" placeholder="Write something..." />
<Textarea variant="outline" label="Outline" placeholder="Write something..." />
<Textarea variant="ghost" label="Ghost" placeholder="Write something..." />
</div>
</template>Sizes
<script setup lang="ts">
import { Textarea } from 'frappe-ui'
</script>
<template>
<div class="flex flex-col gap-4 w-full max-w-sm">
<Textarea size="sm" label="Small" placeholder="Write something..." />
<Textarea size="md" label="Medium" placeholder="Write something..." />
<Textarea size="lg" label="Large" placeholder="Write something..." />
<Textarea size="xl" label="Extra large" placeholder="Write something..." />
</div>
</template>Labeling
label, description, error, and required are wired into the underlying textarea via the shared labeling contract. Setting error suppresses the description and applies aria-invalid="true".
<script setup lang="ts">
import { computed, ref } from 'vue'
import { Checkbox, Textarea } from 'frappe-ui'
const bio = ref('')
const required = ref(true)
const showError = ref(false)
const error = computed(() => (showError.value ? 'Bio cannot be empty.' : ''))
</script>
<template>
<div class="flex gap-8 items-start">
<Textarea
v-model="bio"
label="Bio"
description="Tell us a bit about yourself."
:error="error"
:required="required"
placeholder="Write something..."
class="w-72"
/>
<div
class="flex flex-col gap-2 items-start border-l border-outline-gray-2 pl-6"
>
<Checkbox v-model="required" label="required" />
<Checkbox v-model="showError" label="show error" />
</div>
</div>
</template>States
<script setup lang="ts">
import { Textarea } from 'frappe-ui'
</script>
<template>
<div class="flex flex-col gap-4 w-full max-w-sm">
<Textarea label="Default" placeholder="Write something..." />
<Textarea label="Required" required placeholder="Write something..." />
<Textarea label="Disabled" disabled placeholder="Write something..." />
<Textarea
label="With error"
error="Bio cannot be empty."
placeholder="Write something..."
/>
</div>
</template>API Reference
Show types
import type { InputSize, InputVariant } from '../../composables/inputTypes'
import type { InputLabelingProps } from '../../composables/useInputLabeling'
export interface TextareaProps extends InputLabelingProps {
/** Controls the visual size of the textarea. */
size?: InputSize
/** Visual style variant. */
variant?: InputVariant
/** Placeholder text shown when empty. */
placeholder?: string
/** Disables user interaction. */
disabled?: boolean
/** Bound value of the textarea. */
modelValue?: string
/** Debounce delay (ms) before emitting value updates. */
debounce?: number
/** Number of visible text rows. */
rows?: number
}
export interface TextareaEmits {
/** Fired when the textarea value changes. */
'update:modelValue': [value: string]
}Controls the visual size of the textarea.
Visual style variant.
Placeholder text shown when empty.
Disables user interaction.
Bound value of the textarea.
Debounce delay (ms) before emitting value updates.
Number of visible text rows.
Label rendered above (or beside, for binary controls) the input.
Helper text rendered below the input. Hidden when `error` is set.
Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. May be either a string or an `Error` object whose `messages?: string[]` is rendered as stacked lines (with `Error.message` as the fallback).
Marks the field as required. Renders an asterisk next to the label and forwards `required` / `aria-required` to the underlying control.
HTML id of the underlying control. Auto-generated via `useId()` if omitted.
| Slot | Payload |
|---|---|
label | { required: boolean; } Overrides the rendered label content. Receives `{ required }`. |
description | — Overrides the rendered description content. |
Overrides the rendered label content. Receives `{ required }`.
Overrides the rendered description content.
| Event | Payload |
|---|---|
update:modelValue | [value: string] Fired when the model value changes. |
Fired when the model value changes.