TextArea

Capture free-form text that spans multiple lines, such as descriptions and comments.

0/120

Installation

  1. Install the package.
npm install @hashintel/ds-components
  1. Import the component.
import { useState } from "react";

import { TextArea } from "@hashintel/ds-components";

export const EntityDescriptionField = () => {
  const [description, setDescription] = useState("");

  return (
    <TextArea
      value={description}
      onChange={setDescription}
      placeholder="Describe this entity type…"
      rows={4}
    />
  );
};

When to use

  • Do: Use TextArea for free-form text that runs longer than a few words: descriptions, notes, comments, feedback.
  • Do: Use autoResize for composer-style inputs — comments, chat messages — where the field should grow with the text.

When not to use

  • Don't: Don't use TextArea for single-line values such as names, emails or URLs — use TextInput.
  • Don't: Don't ask users to type what they could pick — for a known set of options use Select, Combobox or RadioGroup.
  • Don't: Don't use it for formatted text — TextArea is plain text only; reach for a dedicated rich-text editor.

Examples

Basic

The default field is bordered, md-sized and three rows tall, and fills the width of its container.

Invalid

Set invalid when the value fails validation — the border turns red and aria-invalid is set. Pair it with a visible error message, such as Form.Field's errors.

Disabled

Disabled fields keep their value visible but grey out and stop accepting focus. Use disabled only while editing is temporarily unavailable — for values the viewer can never edit, prefer readonly.

Read-only

readonly drops the field styling entirely and renders the value as plain text, preserving line breaks — the same content without the affordance to edit. Unlike the native readOnly attribute, the result is no longer a form control: it isn't focusable and doesn't submit.

Tracks every research paper the lab has published, with links to authors and funding sources.

Subtle variant

subtle removes the border and background so the field reads as page text — for editing content in place, such as an entity description on its own page. Hovering reveals a faint border; focusing restores a solid field.

Sizes

size sets the text style and padding; md is the default. Match the size of neighbouring inputs, and use sm and below in dense chrome such as side panels and table cells.

Rows

rows sets the visible height in text lines (default 3) — the field doesn't grow with content unless autoResize is set; longer text scrolls. Match it to the expected length of the answer.

Resizing

resize sets which directions the drag handle allows: vertical (the default), horizontal, both, or none. Prefer vertical — it lets users make room without disturbing the surrounding layout; use none when the layout is fixed.

Auto-resize

autoResize grows and shrinks the field with its content instead of scrolling — right for composer-style inputs. rows becomes the minimum height, and manual resizing is disabled.

Character limit

characterLimit renders a counter below the field. The limit is soft: typing past it is never blocked — the counter turns red so the writer can trim, and your validation enforces the limit on submit.

42/80
103/80

In a form field

Inside a Form.Field the label is associated with the textarea automatically — no htmlForId needed. See the Form docs for descriptions, errors and layout.

Shown on the entity type's page and in search results.

Behavior

  • Clicking anywhere inside the field's box, padding included, focuses the <textarea>.
  • characterLimit never sets the native maxLength attribute, so typing and pasting past the limit always work — enforce the limit in validation.

Content

  • Make the placeholder a prompt for the content, sentence case, ending with an ellipsis when it invites typing: "Describe this entity type…".
  • Never put the label or requirements in the placeholder — it disappears as soon as the user types. Put requirements in the Form.Field description.
  • State character limits in the field's description and repeat them in the error: "Description must be 280 characters or fewer."

Accessibility

TextArea renders a native <textarea>, which carries the standard text-editing semantics and keyboard behavior.

What TextArea provides

  • Inside a Form.Field it adopts the field's generated id, so the label is associated automatically.
  • The character counter announces politely only once the limit is exceeded, instead of narrating every keystroke.

What you must do

  • Label every field: wrap it in a Form.Field, or set aria-label when a visible label is impossible — a placeholder is not a label.
  • Pair invalid with a visible error message, such as Form.Field errors — the red border alone doesn't say what's wrong.
  • State the character limit in the field's description — until it's exceeded, the counter is visual only.

API reference

PropTypeDescription
value
string |⁠ null |⁠ undefined
onChange
(value: string, event: ChangeEvent<HTMLTextAreaElement, Element>) => void
placeholder
string
rows
number
default: 3
readonly
boolean
resize
"none" |⁠ "both" |⁠ "horizontal" |⁠ "vertical"
default: "vertical"
autoResize
boolean
default: false
variant
"subtle" |⁠ "default"
default: "default"
align
"left" |⁠ "right" |⁠ "center"
default: "left"
onClick
MouseEventHandler<Element>
onKeyDown
KeyboardEventHandler<Element>
characterLimit
number
spellcheck
boolean
includeCharCountHeight
boolean
default: false
name
string
onFocus
FocusEventHandler<HTMLTextAreaElement>
onBlur
FocusEventHandler<HTMLTextAreaElement>
invalid
boolean
autoFocus
boolean |⁠ "never"
disabled
boolean
required
boolean
size
"xxs" |⁠ "xs" |⁠ "sm" |⁠ "md" |⁠ "lg"
default: "md"

Was this page helpful?

On this page