Skip to main content

Text Area

Text Area is a form control for entering several lines of text, like describing a project or leaving feedback. It pairs the textarea with a label and helper text, and can grow as people type.

Import

import { TextArea } from '@vortexlabs/vortex';
import type { TextAreaProps } from '@vortexlabs/vortex';

Allied components

Other links

Summarize the goal in a few sentences.
<Stack
  width="440px"
  maxWidth="100%"
>
  <TextArea.Root
    size="md"
    variant="outline"
  >
    <TextArea.Label>Project description</TextArea.Label>
  <TextArea.Input name="playground-description" placeholder="What will this project achieve?" />
  <TextArea.HelperText>Summarize the goal in a few sentences.</TextArea.HelperText>
  <TextArea.ErrorMessage>Add a project description.</TextArea.ErrorMessage>
  </TextArea.Root>
</Stack>

Features

  • Supports outline and fill variants with responsive sizes.
  • Grows with its content when resize is auto.
  • Shows helper text and error messages under the textarea.
  • Accepts native attributes such as maxLength.
  • Supports controlled and uncontrolled values.
  • Supports disabled and required states.

Anatomy

Root links the label, helper text, and error to the textarea, Label names it, and Input is the textarea and requires name. HelperText is optional.

<TextArea.Root>
  <TextArea.Label>Project description</TextArea.Label>
  <TextArea.Input name="description" />
  <TextArea.HelperText>Summarize the goal in a few sentences.</TextArea.HelperText>
</TextArea.Root>

Variants

Text Area has two visual styles: outline and fill. The default is outline.

<TextArea.Root variant="outline">
  <TextArea.Label>Outline</TextArea.Label>
  <TextArea.Input name="outline-notes" placeholder="Add project notes" />
</TextArea.Root>
<TextArea.Root variant="fill">
  <TextArea.Label>Fill</TextArea.Label>
  <TextArea.Input name="fill-notes" placeholder="Add project notes" />
</TextArea.Root>

Sizes

Root size scales the text, spacing, and label. The default is md.

<TextArea.Root size="sm">
  <TextArea.Label>Small</TextArea.Label>
  <TextArea.Input name="small-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>
<TextArea.Root size="md">
  <TextArea.Label>Medium</TextArea.Label>
  <TextArea.Input name="medium-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>

Responsive

size also accepts a breakpoint object.

<TextArea.Root size={{ xs: "sm", md: "md" }}>
  <TextArea.Label>Notes</TextArea.Label>
  <TextArea.Input name="responsive-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>

Automatic Height

Input rows sets its height, 3 by default. Root resize="auto" grows the textarea from its rows height as people type. Otherwise it scrolls longer text. Dragging to resize is disabled.

<TextArea.Root resize="auto">
  <TextArea.Label>Growing notes</TextArea.Label>
  <TextArea.Input name="growing-notes" rows={2} placeholder="Add several lines of notes" />
</TextArea.Root>
<TextArea.Root>
  <TextArea.Label>Fixed-height notes</TextArea.Label>
  <TextArea.Input name="fixed-notes" rows={2} placeholder="Add several lines of notes" />
</TextArea.Root>

Controlled Value and Character Limit

Use value with onChange to control the text. Set limits like maxLength in Input attributes and count from the same state.

0 / 160 characters
"use client";

import { TextArea } from "@vortexlabs/vortex";
import { useState } from "react";

export const TextAreaCountExample = () => {
  const [value, setValue] = useState("");
  return (
    <TextArea.Root resize="auto">
      <TextArea.Label>Project summary</TextArea.Label>
      <TextArea.Input
        name="summary"
        value={value}
        onChange={({ value }) => setValue(value)}
        attributes={{ maxLength: 160 }}
      />
      <TextArea.HelperText>{value.length} / 160 characters</TextArea.HelperText>
    </TextArea.Root>
  );
};

Validation

Root error marks the textarea invalid and shows TextArea.ErrorMessage; helper text stays visible. required only adds native validation, so you decide when to set error.

Explain why this change is needed.Include the impact on your team.
<TextArea.Root error required>
  <TextArea.Label>Reason for the change</TextArea.Label>
  <TextArea.Input name="change-reason" />
  <TextArea.ErrorMessage>Explain why this change is needed.</TextArea.ErrorMessage>
  <TextArea.HelperText>Include the impact on your team.</TextArea.HelperText>
</TextArea.Root>

Disabled and Read Only

Root disabled blocks editing and focus. readOnly in Input attributes keeps the text focusable and selectable.

<TextArea.Root disabled>
  <TextArea.Label>Locked notes</TextArea.Label>
  <TextArea.Input name="locked-notes" defaultValue="This project has been archived." />
</TextArea.Root>
<TextArea.Root>
  <TextArea.Label>Release notes</TextArea.Label>
  <TextArea.Input name="release-notes" defaultValue="Added project templates and improved search." attributes={{ readOnly: true }} />
</TextArea.Root>

Accessibility

Key
Description
Tab
Move focus to the textarea. Disabled fields are skipped.
Include TextArea.Label; a placeholder doesn't replace it. Helper text and the error message are linked to the textarea automatically.
Screen readers announce TextArea.ErrorMessage when it appears.