Skip to content

Textarea ​

A multi-line text field — for longer input like messages, descriptions, or notes. It mirrors Input: same v-model binding, same variants, and the same Field integration for labels, descriptions, and error states.

Set the visible height with rows. Like the other controls it's label-less — pair it with a Label, or wrap it in a Field for the full labelled pattern.

Usage ​

Bind the value with v-model.

BasicA multi-line text field.
<script setup lang="ts">
import { ref } from "vue";
import { Textarea } from "@dlbcodes/ui";

const value = ref("");
</script>

<template>
    <div class="w-full max-w-md">
        <Textarea v-model="value" placeholder="Write a message…" />
    </div>
</template>

Inside a Field ​

Wrap it in a Field for a label, description, and the accessibility wiring — exactly like Input.

With FieldLabel, textarea, and description, auto-wired.
<script setup lang="ts">
import { ref } from "vue";
import {
    Textarea,
    Field,
    FieldLabel,
    FieldContent,
    FieldDescription,
    FieldError,
} from "@dlbcodes/ui";

const bio = ref("");
</script>

<template>
    <Field class="w-full max-w-md">
        <FieldLabel>Bio</FieldLabel>
        <FieldContent>
            <Textarea
                v-model="bio"
                :rows="4"
                placeholder="Tell us about yourself…"
            />
            <FieldDescription>
                A short description for your profile.
            </FieldDescription>
        </FieldContent>
    </Field>
</template>

Error state ​

Inside a Field, setting invalid applies the error styling to the textarea and wires its aria-describedby to the FieldError — so the problem is announced to screen readers. Standalone, you can set invalid on the textarea directly.

ErrorInvalid state with an error message.
<script setup lang="ts">
import { ref } from "vue";
import {
    Textarea,
    Field,
    FieldLabel,
    FieldContent,
    FieldDescription,
    FieldError,
} from "@dlbcodes/ui";

const feedback = ref("Too short");
</script>

<template>
    <Field invalid class="w-full max-w-md">
        <FieldLabel>Feedback</FieldLabel>
        <FieldContent>
            <Textarea
                v-model="feedback"
                :rows="3"
                placeholder="Share your thoughts…"
            />
            <FieldDescription>At least 20 characters.</FieldDescription>
            <FieldError>Your feedback is too short.</FieldError>
        </FieldContent>
    </Field>
</template>

Auto-resize ​

Set autosize and the textarea grows as you type, starting from the rows height and expanding to fit its content. Past a maximum height it stops growing and scrolls instead, so a long entry never takes over the page.

AutosizeGrows from the minimum, caps, then scrolls.
<script setup lang="ts">
import { ref } from "vue";
import { Textarea } from "@dlbcodes/ui";
const value = ref("");
</script>
<template>
    <div class="w-full max-w-md">
        <Textarea
            v-model="value"
            autosize
            :rows="4"
            placeholder="Type several lines — I grow…"
        />
    </div>
</template>

Sizes ​

size takes the same values as Input: sm, base, lg and xl. Unlike an input, a textarea's height comes from rows (and its content, with autosize), so size changes the text size, padding and corners, not the height. Corners follow the theme's --radius.

Props ​

PropTypeDefaultDescription
modelValuestring | number | null—The value. Use with v-model.
rowsnumber4Visible height in text rows. Acts as the minimum height when autosize is on.
autosizebooleanfalseGrows with content from the rows height up to a maximum, then scrolls.
variant"primary" | "contrast""primary"Visual style (shares Input's variants).
size"sm" | "base" | "lg" | "xl""base"Field size (shares Input's sizes). Sets text size, padding and corners; the height comes from rows.
placeholderstring—Placeholder text.
disabledboolean—Disables the field. Inherited from a surrounding Field.
requiredboolean—Marks required. Inherited from a Field.
invalidboolean—Applies error styling. Inherited from a Field's error state.
classstring—Classes merged onto the wrapper.

Accessibility ​

  • Give it a name: pair with a Label or wrap in a Field. A bare textarea with only a placeholder isn't accessibly labelled.
  • Inside a Field, aria-invalid, aria-required, and aria-describedby are wired automatically.