Textarea

A multiline text field that passes through native textarea attributes.

Overview

Textarea renders a native textarea. It uses the same border, type size, focus ring, and disabled treatment as Input, with a minimum height and vertical resizing.

Preview

Customize

Show Count
Max Rows
2
Rows
2
Disabled
Required
Placeholder

Installation

Add the component with the CLI. It copies the files in and installs anything they depend on.

npx vinyaas add textarea

Usage

import { Textarea } from "@/components/ui/textarea"; export function MessageField() { return ( <label htmlFor="message" className="flex flex-col gap-2 text-sm"> Message <Textarea id="message" name="message" rows={4} placeholder="Write a message" /> </label> ); }

Examples

Basic

A multiline field. It can be resized vertically.

Character count

With maxLength and showCount, the current length and limit sit just under the field's bottom-right corner, outside the box. The counter turns destructive at the limit and is linked with aria-describedby.

23/120

Auto-grow with maxRows

With maxRows the field starts at rows lines, grows as you type, and starts scrolling once it reaches maxRows. Type a few lines to see it.

Label

Associate the label with htmlFor and id.

Description

aria-describedby connects the help text to the field.

Visible to the project team.

Rows

rows sets the initial height. The field still has a minimum height from its styles.

Required

required is the native constraint.

Disabled

A disabled textarea cannot be edited and uses the not-allowed cursor.

Invalid

aria-invalid is forwarded. Textarea does not change its border for that state.

In practice

A feedback note with a labelled textarea and Submit and Cancel actions.

API

Other attributes for the underlying element are passed through.

NameTypeDefaultDescription
classNamestring—Merged onto the textarea with cn.
showCountbooleanfalseShows a current/maxLength counter pinned just under the field's bottom-right corner, outside the box. Without maxLength it shows only the current length.
maxRowsnumber—Grow with the content up to this many rows, then scroll. rows sets the starting height (default 1 while growing). Turns off manual resizing.
containerClassNamestring—Merged onto the wrapper that holds the field and counter when showCount is set. The counter is anchored to this wrapper, so set width here rather than on className.
rowsnumber—Native row count. The field also has a minimum height.
colsnumber—Native column count.
disabledboolean—Native disabled state. Uses a not-allowed cursor and reduced opacity.
requiredboolean—Native required state.
placeholderstring—Placeholder text. It is not a label.
valuestring—Controlled value. Pair it with onChange.
defaultValuestring—Uncontrolled initial value.
aria-invalid"true" | "false"—Passed through. Textarea does not add a separate invalid color.

Accessibility

Textarea is a native textarea. It does not add an ARIA role.

  • Name it with a label and matching id, or with aria-label.
  • Placeholder text is not a replacement for the label.
  • Keyboard behavior is the browser default, including line breaks.
  • disabled prevents editing. Focus uses a visible focus-visible ring.
  • aria-invalid and aria-describedby are passed through.