Textarea
v0.0.10
mix mishka.ui.gen.headless textarea
Overview of the Phoenix and LiveView Headless Textarea Component
The Mishka Chelekom Headless Textarea is a multi-line text control for Phoenix forms. It ships no styling. The root is a div that acts as the control box, and the native textarea sits inside it. Paint the border and background on the root and leave the textarea transparent, and a browser resize handle will not cut across the border.
Hand it a form field with field={@form[:bio]} and it takes its id, name, value and errors from the form. Without a field, pass name and value yourself. With autosize the box grows with its content between min_rows and max_rows, driven by the Autosize LiveView hook. Without autosize there is no JavaScript at all. Each part takes its own class attribute: class for the root and textarea_class for the textarea.
Base UI Textarea example - multi-line field (Phoenix headless)
Base UI Textarea example - multi-line field (Phoenix headless)
<.textarea
id="baseui-textarea-hero"
name="bio"
rows={3}
placeholder="Tell us about yourself"
class="w-full max-w-80 rounded-md border border-neutral-200 bg-white text-sm text-neutral-950 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-neutral-950 dark:focus-within:outline-white"
textarea_class="w-full bg-transparent p-3 outline-none"
/>Base UI Textarea example - autosize between two and six rows (Phoenix headless)
Base UI Textarea example - autosize between two and six rows (Phoenix headless)
<.textarea
id="baseui-textarea-autosize"
name="notes"
autosize
min_rows={2}
max_rows={6}
placeholder="Keep typing, this grows to six rows, then scrolls"
class="w-full max-w-80 rounded-md border border-neutral-200 bg-white text-sm text-neutral-950 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-neutral-950 dark:focus-within:outline-white"
textarea_class="w-full bg-transparent p-3 outline-none"
/>Using it in a form
<.form for={@form} phx-change="validate" phx-submit="save">
<.textarea
field={@form[:bio]}
rows={3}
placeholder="Tell us about yourself"
class="..."
textarea_class="..."
/>
</.form>With field, errors show up only after the user has touched the field, so an untouched form shows no errors. Pass errors yourself with a plain name and a non-empty list marks the control invalid. valid marks it valid, and describedby sets aria-describedby for a hint or an error message. disabled, readonly and required map to the native attributes, and readonly blocks editing but keeps the field focusable. Attributes such as maxlength, minlength, autocomplete, autofocus, spellcheck, wrap, form and phx-change pass through to the textarea.
Rows, autosize and resize
rows sets the visible rows. When you leave it out, the textarea starts at min_rows, which defaults to 2. With autosize the hook measures the content on every input and after every server patch, and sets the height between min_rows and max_rows. Once max_rows is reached the textarea scrolls instead of growing. Leave max_rows unset and it grows without a limit.
resize is vertical (the default), none, horizontal or both. It writes data-resize on the textarea and leaves the styling to you, for example resize-y data-[resize=none]:resize-none data-[resize=horizontal]:resize-x data-[resize=both]:resize. While autosize is on, resize is forced to none, because a resize handle and an autosizing box would overwrite each other's height.
Parts & data attributes
Each part carries a stable data-part and a chelekom-textarea* class you can target. The root reflects the state of the control.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | root | data-invalid, data-valid, data-disabled, data-readonly, data-required, data-autosize | The control box. Paint the border and background here. |
| Textarea | textarea | aria-invalid, aria-describedby, data-resize, data-min-rows and data-max-rows (with autosize) | The native textarea. It carries the Autosize hook only when autosize is set. |
Accessibility
The control is a native textarea, so Tab focuses it, Enter adds a new line and text entry works as in any browser. Give it a visible label, for example with a Field, and use describedby for hints and errors. An invalid control sets aria-invalid="true". Autosize changes the height only, so keyboard and screen reader behavior stays native.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | No | Unique id; taken from the form field when one is given |
field
|
Phoenix.HTML.FormField
| — | — | No | A form field struct — supplies id, name, value and errors |
name
|
string
| — | — | No | Textarea name (ignored when `field` is given) |
value
|
any
| — | — | No | Textarea value (ignored when `field` is given) |
errors
|
list
|
[]
| — | No | Error messages; a non-empty list marks it invalid |
valid
|
boolean
|
false
| — | No | Mark the control valid (data-valid) |
disabled
|
boolean
|
false
| — | No | Disable the control (data-disabled) |
readonly
|
boolean
|
false
| — | No | Block editing but keep it focusable |
required
|
boolean
|
false
| — | No | Require a value for form submit |
placeholder
|
string
| — | — | No | Placeholder text |
rows
|
integer
| — | — | No | Visible rows (native) |
autosize
|
boolean
|
false
| — | No | Grow with the content between `min_rows` and `max_rows` (adds the Autosize hook) |
min_rows
|
integer
|
2
| — | No | Smallest height while autosizing |
max_rows
|
integer
| — | — | No | Largest height while autosizing; nil is unbounded |
resize
|
string
|
vertical
|
noneverticalhorizontalboth
| No | Native resize handle direction; forced to `none` while autosizing |
describedby
|
string
| — | — | No | Id(s) of the description/error elements |
class
|
any
| — | — | No | Extra classes for the control root |
textarea_class
|
any
| — | — | No | — |
rest
|
global
| — | — | No | Any textarea/global attrs, e.g. phx-change |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
textarea
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless textarea