TextArea

Multi-line text that grows as you type. Labels, descriptions, and errors belong to Field. For a single line, use Input.

Installation

bun add @harmo-ui/css @harmo-ui/react

Usage

import { Field, TextArea } from "@harmo-ui/react";

<Field label="Message">
  <TextArea name="message" maxLength={500} placeholder="Hello, your order has shipped…" />
</Field>

Examples

This site is using your theme

With a counter

It starts one line tall and grows as you type, up to 150px, then scrolls. The counter under it, connected with aria-describedby, counts toward maxlength.

0/500

<Field label="Message">
  <TextArea
    name="message"
    maxLength={500}
    placeholder="Hello, your order has shipped…"
  />
</Field>

Long text

Already tall with its text. Dragging the corner handle can make it taller, up to 400px or half the window, whichever is less.

<Field label="Saved reply">
  <TextArea
    name="reply"
    defaultValue="Thanks for reaching out! Your order left our warehouse this morning and should arrive within three working days. You can follow it with the tracking link in your confirmation email, and reply here if anything looks off."
  />
</Field>

Custom maximum height

--htextarea-max-height sets how tall dragging the corner can make it; here 200px instead of 400px or half the window.

<Field label="Email footer">
  <TextArea
    name="footer-text"
    style={{ "--htextarea-max-height": "200px" } as CSSProperties}
    defaultValue="Acme Support · Mon–Fri, 9:00–18:00"
  />
</Field>

Invalid

aria-invalid="true" turns the border red, as for an Input.

Optional

Remove card numbers from notes.

<Field
  label="Internal note"
  optional="Optional"
  error="Remove card numbers from notes."
>
  <TextArea
    name="internal-note"
    defaultValue="Customer paid with card 4242 4242 4242 4242."
  />
</Field>

Read-only and disabled

As for an Input: both get a gray background, and only the read-only one can be focused and copied from.

<>
  <Field label="Original message">
    <TextArea
      name="original-message"
      defaultValue="Where is my order?"
      readOnly
    />
  </Field>
  <Field label="Signature">
    <TextArea name="signature" defaultValue="The Acme team" disabled />
  </Field>
</>

API reference

React

<TextArea> renders the <textarea>, and with maxLength the counter, connected through aria-describedby and kept current as you type and after a form reset. In a Field, it takes the field's id and descriptions. Its props are the textarea's attributes, with value or defaultValue.

HTML

A <textarea class="htextarea">, with an optional .htextarea-counter right after it, named by a <label for>. Load textarea.css; field.css for its label and messages.

HookEffect
aria-invalid="true", readonly, disabled, placeholderAs for Input
.htextarea-counterA character count under the box
--htextarea-max-heightHow tall dragging can make it; default min(400px, 50dvh)

A script is only needed for the counter's text. See TextArea's full contract.

Accessibility

Name it with a <label for> in a Field. Connect the counter with aria-describedby, so screen readers read it on focus.