@cf/ui

@cf/textarea

Textarea

A multi-line text field that grows with its content, with focus and invalid states built in.

Describe what the image shows, not its file name.

Stock shadcn base-nova. field-sizing-content means it grows with what you type, with a min-h-16 floor and no ceiling, so give it a max-h-* wherever height matters. The chat composer uses max-h-40.

It styles aria-invalid itself (destructive border and ring), which Input doesn't yet. Nothing on the site uses Textarea on its own right now: the only multi-line field is the chat composer, which goes through InputGroupTextarea.

import { Textarea } from "@/components/ui/textarea";
 
<Textarea aria-label="Message" className="max-h-40" rows={1} />

Rules

The same rules ship in DESIGN.md and the MCP server, for the agents building with this.

  • must

    Pair every Textarea with a FieldLabel or Label via htmlFor and id, or give it an aria-label when there's no visible label.

    label-every-textarea

  • must

    Keep the text-base md:text-sm pairing if you override the text size; never go under 16px below md.

    iOS zooms into any field smaller than 16px and doesn't zoom back out.

    keep-16px-on-touch

  • should

    Set a max-h-* class when the textarea sits in a fixed layout, because field-sizing-content lets it grow without limit.

    cap-the-growth

  • must

    Inside an InputGroup, use InputGroupTextarea instead of Textarea.

    use-group-textarea-in-groups

Install

bunx shadcn@latest add @cf/textarea

Needs the @cf registry in your components.json once. The theme and any sibling components come along automatically.

Source

textarea.tsxShow
import { cn } from "cn";
import type * as React from "react";
 
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
  return (
    <textarea
      className={cn(
        "field-sizing-content flex min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 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:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 dark:disabled:bg-input/80",
        className
      )}
      data-slot="textarea"
      {...props}
    />
  );
}
 
export { Textarea };