|Design System

AI Component

Textarea

Multi-line text input with optional auto-expand behavior — the foundation of chat input bars.

Preview

Source

Full component implementation using the design system tokens.

tsx
"use client";

import { useRef, useEffect } from "react";

export function DSTextarea({
  label,
  helperText,
  error,
  autoExpand = false,
  ...props
}: {
  label?: string;
  helperText?: string;
  error?: string;
  autoExpand?: boolean;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>) {
  const ref = useRef<HTMLTextAreaElement>(null);
  const hasError = !!error;

  useEffect(() => {
    if (autoExpand && ref.current) {
      const el = ref.current;
      const handleInput = () => {
        el.style.height = "auto";
        el.style.height = `${el.scrollHeight}px`;
      };
      el.addEventListener("input", handleInput);
      return () => el.removeEventListener("input", handleInput);
    }
  }, [autoExpand]);

  return (
    <div className="flex flex-col gap-1.5 w-full">
      {label && (
        <label className="text-sm font-medium text-foreground">{label}</label>
      )}
      <textarea
        ref={ref}
        className={`w-full px-3 py-2 text-sm text-foreground bg-surface border rounded-lg outline-none transition-colors placeholder:text-tertiary resize-none ${
          hasError
            ? "border-red-500 focus:border-red-500"
            : "border-overlay/10 focus:border-accent"
        } ${autoExpand ? "overflow-hidden" : ""}`}
        rows={props.rows ?? 3}
        {...props}
      />
      {(helperText || error) && (
        <p className={`text-xs ${hasError ? "text-red-500" : "text-tertiary"}`}>
          {error || helperText}
        </p>
      )}
    </div>
  );
}

Props

All available props with types and defaults.

PropTypeDescription
labelstringLabel text above the textarea
helperTextstringHelper text below the textarea
errorstringError message
autoExpandbooleanAuto-grows height to fit content
rowsnumberInitial visible rows
placeholderstringPlaceholder text

Variants

Default

Standard multi-line input with label.

tsx
<DSTextarea
  label="System prompt"
  placeholder="You are a helpful assistant..."
  rows={3}
/>

Auto-expand

Grows with content — ideal for chat input bars.

tsx
<DSTextarea
  placeholder="Type a message..."
  autoExpand
  rows={1}
/>

Error

Validation error state.

Template must include {input} variable

tsx
<DSTextarea
  label="Prompt template"
  error="Template must include {input} variable"
/>

Prompt Guide

Prompt Guide — Textarea

Use for

  • Chat input bars (with autoExpand)
  • System prompt editors
  • Prompt template editors
  • Feedback and comment inputs

Don't use for

  • Single-line inputs — use Input component
  • Code editors — use a dedicated code editor component
  • Rich text — textarea is plain text only

AI Context

The Textarea with autoExpand is the chat input bar. Start at 1 row, grow as the user types, submit on Enter (Shift+Enter for newline). For system prompt editors, use a fixed height (rows=6+) with scroll. The auto-expand behavior uses a ref to measure scrollHeight — no layout thrashing.