Textarea
View as MarkdownA multi-line text input that works with Field, with optional word count, screen reader announcements, and submit-on-Enter.
Features
Permalink to heading "Features"- Works standalone or nested directly inside
ui:field.root- nofield.controlwrapper needed - Auto-resizes to fit its content via CSS
field-sizing: content- no@zag-js/auto-resizeor JS involved, see the MDN docs for browser support - Optional
submitOnprop to submit the nearest form on Enter or Cmd/Ctrl+Enter instead of inserting a newline - Optional
transformcallback to sanitize/reformat the value as the user types, with cursor position preserved - Optional
wordCountpart rendering a translatable "42 / 250 characters" style counter, driven bymaxLength - Word count updates are announced to screen readers by default through the page's shared live region, debounced so it doesn't spam assistive tech on every keystroke - pass
announce="{false}"to turn it off
<primitives:textarea.root>
<primitives:textarea.label />
<primitives:textarea.textarea />
<primitives:textarea.wordCount />
</primitives:textarea.root>
Installation
Permalink to heading "Installation"typo3 ui:add textarea
Please copy the files manually from GitHub into your project.
Read more about installing Components and Primitives.
Examples
Permalink to heading "Examples"With Field
Permalink to heading "With Field"Nest ui:textarea.root directly inside ui:field.root - it inherits name, disabled, required, invalid and aria-describedby automatically, the same way ui:input/ui:select do. Use the primitive's own label part (nested inside root) rather than field.label - it targets the right control automatically.
With Word Count
Permalink to heading "With Word Count"Pass maxLength and add the wordCount part wherever you want it - it doesn't need to be a direct sibling of textarea.
Submit on Enter
Permalink to heading "Submit on Enter"Pass submitOn="{f:constant(name: 'Jramke\FluidPrimitives\Enum\TextareaSubmitOn::ModEnter')}" to submit the nearest <form> on Cmd/Ctrl+Enter instead of inserting a newline - plain Enter still inserts a newline. Use TextareaSubmitOn::Enter for the opposite: plain Enter submits, Shift+Enter inserts a newline. Wrap the textarea in ui:form.root (or any native <form>) for the submit to actually go anywhere - submitOn just calls closest('form')?.requestSubmit().
With a Transform Callback
Permalink to heading "With a Transform Callback"transform runs on every native input event, before the value is committed - return the value that should actually be written back to the textarea, with cursor position preserved across the rewrite. Because a real function can't cross the PHP → client JSON boundary, this can only be set by constructing Textarea yourself in a custom entry file, rather than as a Fluid prop. Type lowercase below - it's uppercased as you type:
API Reference
Permalink to heading "API Reference"The following tables cover the available props of the Fluid Primitives.
textarea.root
Permalink to heading "textarea.root"Provides shared textarea state and wraps all related parts. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
placeholder | stringPlaceholder text shown when the textarea is empty. | No | - |
autocomplete | stringHints for browser autofill, e.g. street-address. See the [HTML spec](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) for the full list of tokens. | No | - |
name | stringThe name attribute of the textarea. Useful for form submission. Inherited from a surrounding field when available. | No | - |
disabled | booleanWhether the textarea is disabled. Inherited from a surrounding field when available. | No | - |
invalid | booleanWhether the textarea value is invalid. Inherited from a surrounding field when available. | No | - |
required | booleanWhether the textarea is required. Inherited from a surrounding field when available. | No | - |
readOnly | booleanWhether the textarea is readonly. Inherited from a surrounding field when available. | No | - |
defaultValue | stringThe initial value of the textarea when rendered. Use when you don't need to control the value of the textarea. Inherited from a surrounding field when available. | No | '' |
maxLength | integerThe maximum number of characters allowed. Also drives the wordCount part, e.g. '42 / 250 characters'. | No | - |
rows | integerThe number of visible text lines. | No | - |
submitOn | Enum\TextareaSubmitOnSubmits the nearest form on a keypress instead of inserting a newline: Enter submits on plain Enter (Shift+Enter still inserts a newline), ModEnter submits on Cmd/Ctrl+Enter (plain Enter always inserts a newline). Unset (the default) never intercepts Enter. | No | - |
translations | arraySpecifies the localized word count string. Use `f:translate` for per-template localization overrides when needed. | No | - |
announce | booleanWhether the word count is announced to assistive tech as the user types. Set to false to stay silent. | No | true |
announceDebounce | integerMilliseconds to debounce word count announcements by, so rapid typing doesn't spam assistive tech. Set to 0 to announce every change immediately. | No | 600 |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
rootId | stringThe root ID of the component, used for hydration and identification. | No | - |
ids | arrayThe IDs of of the component parts for composition. | No | [] |
autoMount | booleanWhether the client initializes the component on its own. Set it to false to mount it yourself with `mount()` | No | true |
class | stringThe CSS class(es) to be applied to the component. | No | - |
Rendered data attributes
| Attribute | Description |
|---|---|
data-invalid | Present when invalid |
data-disabled | Present when disabled |
data-readonly | Present when read-only |
textarea.label
Permalink to heading "textarea.label"Labels the textarea. Renders a <label> element.
| Name | Description | Required | Default |
|---|---|---|---|
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
Rendered data attributes
| Attribute | Description |
|---|---|
data-invalid | Present when invalid |
data-disabled | Present when disabled |
data-required | Present when required |
textarea.textarea
Permalink to heading "textarea.textarea"The editable textarea. Renders a <textarea> element.
| Name | Description | Required | Default |
|---|---|---|---|
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
Rendered data attributes
| Attribute | Description |
|---|---|
data-invalid | Present when invalid |
data-disabled | Present when disabled |
data-readonly | Present when read-only |
textarea.wordCount
Permalink to heading "textarea.wordCount"Displays the character count, e.g. '42 / 250 characters'. Renders a <span> element.
| Name | Description | Required | Default |
|---|---|---|---|
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
Machine options
Permalink to heading "Machine options"| Name | Description | Default |
|---|---|---|
id | stringThe unique identifier of the textarea. | - |
ids | Record<string, string> | undefinedThe ids of the parts other elements reference: textarea (the for of its label) and wordCount. | - |
name | string | undefinedThe name of the textarea, as it is submitted with the form. Taken from the closest field. | - |
disabled | boolean | undefinedWhether the textarea is disabled. Taken from the closest field. | - |
readOnly | boolean | undefinedWhether the textarea is read-only. Taken from the closest field. | - |
required | boolean | undefinedWhether the textarea is required. Taken from the closest field. | - |
invalid | boolean | undefinedWhether the textarea is invalid. Taken from the closest field. | - |
defaultValue | string | undefinedThe initial value of the textarea. | - |
maxLength | number | undefinedThe most characters allowed. It also drives the word count, e.g. 42 / 250 characters. | - |
rows | number | undefinedThe number of visible lines. | - |
submitOn | TextareaSubmitOn | undefinedSubmits the closest <form> on a keypress instead of inserting a newline. 'enter' submits on Enter, Shift+Enter still inserts a newline. 'mod+enter' submits on Cmd or Ctrl+Enter, Enter always inserts a newline. By default Enter is never intercepted. | - |
translations | TextareaTranslations | undefinedThe localized texts of the textarea. | - |
announce | boolean | undefinedWhether the word count is announced to assistive tech. Set to false to stay silent. | true |
announceDebounce | number | undefinedMilliseconds to debounce word count announcements by, so rapid typing doesn't spam assistive tech on every keystroke. Set to 0 to announce every change immediately. | 600 |
transform | ((value: string, event: Event) => string) | undefinedRuns on every native input event, before the value is committed. Return the value to write back to the textarea, e.g. trimmed. The cursor position is kept. It cannot be set from a Fluid template, only by constructing Textarea in your own entry file. | - |
onValueChange | ((details: { value: string }) => void) | undefinedCalled when the value changes. | - |
Machine JavaScript API
Permalink to heading "Machine JavaScript API"| Name | Type | Description |
|---|---|---|
value | string | The current value of the textarea. |
count | number | The number of characters in the value. |
countText | string | null | The word count text, e.g. 42 / 250 characters. null without maxLength or when the text is turned off. |
disabled | boolean | Whether the textarea is disabled. |
readOnly | boolean | Whether the textarea is read-only. |
required | boolean | Whether the textarea is required. |
invalid | boolean | Whether the textarea is invalid. |
name | string | undefined | The name of the textarea. |
maxLength | number | undefined | The most characters allowed. |