TextArea
Capture free-form text that spans multiple lines, such as descriptions and comments.
Installation
- Install the package.
npm install @hashintel/ds-components- 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
autoResizefor 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.
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.
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.
Behavior
- Clicking anywhere inside the field's box, padding included, focuses the
<textarea>. characterLimitnever sets the nativemaxLengthattribute, 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-labelwhen a visible label is impossible — a placeholder is not a label. - Pair
invalidwith a visible error message, such as Form.Fielderrors— 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
| Prop | Type | Description |
|---|---|---|
| value | string | null | undefined | The input value |
| onChange | (value: string, event: ChangeEvent<HTMLTextAreaElement, Element>) => void | The onChange handler |
| placeholder | string | |
| rows | number default: 3 | The number of visible text rows. Acts as the minimum height when autoResize is set. |
| readonly | boolean | Whether editing is disabled. Unlike disabled, strips the input styles and renders the value as plain text. |
| resize | "none" | "both" | "horizontal" | "vertical" default: "vertical" | Which directions the user can manually resize the textarea. Ignored when autoResize is set. |
| autoResize | boolean default: false | Grow the textarea to fit its content instead of scrolling. Disables manual resizing. |
| variant | "subtle" | "default" default: "default" | The textarea's visual style: subtle removes the border so it reads as inline text. |
| align | "left" | "right" | "center" default: "left" | The alignment of the text inside the textarea. |
| onClick | MouseEventHandler<Element> | |
| onKeyDown | KeyboardEventHandler<Element> | |
| characterLimit | number | The character limit surfaced by the CharacterCount. This is a soft limit: typing past it is allowed and the counter turns red, rather than being truncated, so the caller can validate and warn. Setting this renders the counter. It does not set the native maxLength attribute. |
| spellcheck | boolean | |
| includeCharCountHeight | boolean default: false | Whether the character counter reserves vertical space in the layout. |
| name | string | The name of the input |
| onFocus | FocusEventHandler<HTMLTextAreaElement> | The onFocus handler |
| onBlur | FocusEventHandler<HTMLTextAreaElement> | The onBlur handler |
| invalid | boolean | Set to show the input as invalid |
| autoFocus | boolean | "never" | Set to true to make the element focused on mount or 'never' to prevent the item being auto-focused |
| disabled | boolean | Set to show the input as disabled |
| required | boolean | Marks the input as required: sets the native required attribute, so assistive technology announces it and form validation blocks empty submits. Purely functional — the input looks unchanged; pair it with Form.Field's required for the visible mark. |
| size | "xxs" | "xs" | "sm" | "md" | "lg" default: "md" | The size (height) of the element |
Was this page helpful?