rapidUI

Textarea

Multi-line text input.

Installation

pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/textarea.json

Installs to @/components/ui/textarea.

Manual installation

Copy the source into your project:

components/ui/textarea.tsx
import type * as React from 'react'
import { cn } from '@/lib/utils'

function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
	return (
		<textarea
			data-slot="textarea"
			className={cn(
				'flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-background px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground hover:border-primary/90 read-only:cursor-default read-only:border-dashed read-only:bg-muted/50 read-only:hover:border-input focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',
				className,
			)}
			{...props}
		/>
	)
}

export { Textarea }

A styled native HTML textarea element. It grows with its content (field-sizing: content) and has built-in styles for focus, disabled and invalid (aria-invalid) states. Icons, loading indicators and action buttons are composed with InputGroup and InputGroupTextarea.

Features

  • Plain native textarea — all HTML textarea attributes are supported
  • Auto-grows with content via field-sizing-content (minimum height min-h-16)
  • Focus ring, disabled and aria-invalid error styling out of the box
  • Dark mode support
  • Compose icons, text and buttons with InputGroup

Usage

import { Textarea } from '@/components/ui/textarea'
import { Label } from '@/components/ui/label'

// Basic usage
<Textarea placeholder="Describe your question or request…" />

// With label
<div className="grid w-full gap-1.5">
  <Label htmlFor="question">Your question</Label>
  <Textarea id="question" placeholder="Describe your question or request…" />
</div>

// Invalid state
<Textarea aria-invalid />

// Disabled state
<Textarea disabled placeholder="Disabled textarea" />

With an icon or buttons, use InputGroup:

import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from '@/components/ui/input-group'

<InputGroup>
  <InputGroupTextarea placeholder="Write a message to your case handler…" />
  <InputGroupAddon align="block-end">
    <InputGroupButton size="icon-xs" aria-label="Attach a file">
      <PaperclipIcon />
    </InputGroupButton>
  </InputGroupAddon>
</InputGroup>

Examples

Default

A plain textarea. It grows with its content, so there is no need to set rows.

With Label

Inside a Field with a FieldLabel and a FieldDescription with guidance.

Composer

A secure message to a case handler, composed with InputGroup: a header addon, an attach button, and a send button that stays disabled until there is text.

Disabled

Read Only

readOnly shows a dashed border and a muted background while keeping the text selectable – useful for decision texts.

Invalid

Set aria-invalid and point aria-describedby at a FieldError.

Loading

A Spinner and status text in a block-end addon while content is fetched.

With Max Length

A character counter below the field, linked with aria-describedby.

With Validation

Validates when the field loses focus and shows the error with FieldError.

Props

Textarea accepts all native textarea props (React.ComponentProps<'textarea'>), including className. It has no custom props.

Accessibility

  • Uses the native HTML textarea element
  • Pair with a Label via htmlFor / id
  • Use aria-invalid and aria-describedby to announce errors
  • Clear focus indicators and keyboard support

Best Practices

  1. Always use a label; placeholders are supplementary only.
  2. Show a character counter when using maxLength.
  3. Mark invalid fields with aria-invalid and show a clear error message.
  4. Use InputGroup for icons and inline actions.
  • Input
  • Input Group
  • Label
  • Field
  • Form