Qure UI
Components

Textarea

Multi-line text input.

import { Label } from '@/registry/qure/ui/label'import { Textarea } from '@/registry/qure/ui/textarea'export default function TextareaDemo() {  return (    <div className="grid w-full max-w-md gap-2">      <Label htmlFor="impression">Impression</Label>      <Textarea id="impression" placeholder="Describe the findings…" />    </div>  )}

Installation

npx shadcn@latest add https://qure-ui.qure.ai/r/textarea.json

Usage

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

A native <textarea> — Base UI has no primitive for it, because the platform element is already accessible and resizable, and wrapping it would only take those away.

<Label htmlFor="impression">Impression</Label>
<Textarea id="impression" placeholder="Describe the findings…" />

Use it for prose someone will compose: an impression, a handover note, a reason for rejecting a study. It is the wrong control for a value with a shape — a date, a code, an accession number — where an Input both constrains the entry and tells the browser what to autofill.

With a label

import { Label } from '@/registry/qure/ui/label'import { Textarea } from '@/registry/qure/ui/textarea'export default function TextareaDemo() {  return (    <div className="grid w-full max-w-md gap-2">      <Label htmlFor="impression">Impression</Label>      <Textarea id="impression" placeholder="Describe the findings…" />    </div>  )}

min-height is 80px, about three lines, and the browser's resize handle is left alone. Anything shorter suggests a sentence is expected and makes people write one.

Growing with its content

import { Label } from '@/registry/qure/ui/label'import { Textarea } from '@/registry/qure/ui/textarea'export default function TextareaAutogrow() {  return (    <div className="grid w-full max-w-md gap-2">      <Label htmlFor="technique">Technique</Label>      <Textarea        id="technique"        className="field-sizing-content max-h-48 min-h-0 resize-none"        defaultValue="Axial images acquired from the lung apices to the adrenal glands after intravenous contrast."      />    </div>  )}

field-sizing-content lets the box track what has been typed, and a max-h stops it from walking off the screen. Pair it with resize-none, since a box that sizes itself and also has a handle fights whoever drags it. Good for a field that is usually one line and occasionally five; not for a report body, where a fixed, generous box is calmer than one that reflows on every keystroke.

Read-only and disabled

import { Label } from '@/registry/qure/ui/label'import { Textarea } from '@/registry/qure/ui/textarea'export default function TextareaState() {  return (    <div className="grid w-full max-w-md gap-4">      <div className="grid gap-2">        <Label htmlFor="signed-impression">Impression (signed)</Label>        <Textarea          id="signed-impression"          readOnly          className="min-h-16"          defaultValue="No acute cardiopulmonary abnormality."        />      </div>      <div className="grid gap-2">        <Label htmlFor="addendum">Addendum</Label>        <Textarea id="addendum" disabled className="min-h-16" placeholder="Available once the report is signed" />      </div>    </div>  )}

They differ in a way that matters clinically. readOnly keeps the text selectable, copyable and in the tab order — right for a signed impression, which someone may well want to quote. disabled removes it from the tab order and greys it, which is right only for a field that cannot be used yet. A signed report shown as disabled reads as broken.

In a report card

Impression
ACC-482913 · CT Chest
import { Button } from '@/registry/qure/ui/button'import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/registry/qure/ui/card'import { Textarea } from '@/registry/qure/ui/textarea'export default function TextareaCard() {  return (    <Card className="w-full max-w-md">      <CardHeader>        <CardTitle>Impression</CardTitle>        <CardDescription>ACC-482913 · CT Chest</CardDescription>      </CardHeader>      <CardContent>        <Textarea          aria-label="Impression"          className="min-h-32"          defaultValue="8mm solid nodule in the right upper lobe, unchanged from 12 Mar 2025. No pleural effusion."        />      </CardContent>      <CardFooter className="justify-end">        <Button size="sm" variant="tertiary">Save draft</Button>        <Button size="sm">Sign report</Button>      </CardFooter>    </Card>  )}

The composition this component mostly appears in: the subject in the header, the box filling the content, the actions in the footer. Give it a real min-h here — the default three lines are too few for an impression, and the person writing should not have to drag before they can see what they wrote.

Let people resize. Software that decides how much room a radiologist gets to describe a finding is software arguing with its user.

There is no error styling on a textarea yet: the stylesheet covers hover, focus and disabled but has no [data-invalid] rule, so aria-invalid changes nothing visible. Put the error in a message below the field until it does.

API Reference

No primitive and no added props — everything a native <textarea> accepts, including rows, maxLength, readOnly and required. Inside a Base UI Field the label association and validation wiring are supplied for you.

On this page