Text and fields
Text Area
Enter several lines of text, in a field that grows as you type.
Grows as you type, up to six lines.
import { Field, FieldDescription, FieldLabel } from "macbetter/field"
import { TextArea } from "macbetter/text-area"
export default function Example() {
return (
<div style={{ width: "100%", maxWidth: 340 }}>
<Field name="notes">
<FieldLabel>Notes</FieldLabel>
<TextArea placeholder="What changed in this release?" maxRows={6} />
<FieldDescription>Grows as you type, up to six lines.</FieldDescription>
</Field>
</div>
)
}When to use it
Use a text area for notes, descriptions, messages and anything else that can run past one line. It starts at minRows and grows with the text up to maxRows, then scrolls, so a short note stays small and a long one stays readable.
For one line use a Text Field. For text mixed with people or tags use a Token Field.
Usage
import { TextArea } from "macbetter/text-area"TextArea is a native textarea. It grows by default; pass autoResize={false} to keep it at minRows.
Rows and sending
A reply box starts at one row. submitShortcut="enter" sends its form on Return and starts a new line on Shift-Return, as in Messages; "mod+enter" sends on Command-Return instead.
import { TextArea } from "macbetter/text-area"
export default function Example() {
return (
<div style={{ display: "flex", flexDirection: "column", gap: 12, width: "100%", maxWidth: 340 }}>
<TextArea
aria-label="Reply"
minRows={1}
maxRows={4}
placeholder="Reply to Hollis…"
submitShortcut="enter"
/>
<TextArea
aria-label="Description"
minRows={4}
defaultValue="Weekly revenue by region, refreshed every morning from the warehouse."
/>
</div>
)
}Platform behavior
- macOS. The bordered field with 13-point text on 16-point lines and the accent halo while editing.
- iPadOS and iOS. The filled gray field with 17-point text on 22-point lines. A
plaintext area fills a list row with no chrome. - Every platform. There's no resize handle: the field sizes itself, natively where the browser supports
field-sizing.
Accessibility
- It stays a native
textarea, with standard editing, selection and spell checking. - Name it with a Field label or
aria-label; put limits like a character count in the Field's description so they're read with it.
API
TextArea
| Prop | Type | Default | Description |
|---|---|---|---|
minRows | number | 3 | The fewest lines it shows. |
maxRows | number | 10 | The most lines it grows to before it scrolls. |
autoResize | boolean | true | Grows and shrinks with the text. |
variant | "auto" | "bordered" | "filled" | "plain" | "auto" | Bordered on macOS and filled on touch, or a fixed look. |
submitShortcut | "enter" | "mod+enter" | — | Which keys submit its form. |
onValueChange | (value, details) => void | — | Runs on typing, a reset or a controller. |
Data attributes
| Attribute | On | Values |
|---|---|---|
data-variant | TextArea | auto, bordered, filled, plain |
data-filled, data-disabled, data-readonly, data-required | TextArea | Field state |
data-invalid | TextArea | Present inside an invalid Field |
CSS variables
| Variable | macOS | iOS | What it sets |
|---|---|---|---|
--mb-text-area-line | 16px | 22px | Line height, which the row limits multiply |
--mb-text-area-pad-block | 5px | 11px | Top and bottom padding |
--mb-text-area-min-rows, --mb-text-area-max-rows | From props | From props | Row limits |