Fluxon.Components.Textarea (Fluxon v3.1.1)

Provides <.textarea>, a labeled multi-line text input bound to either a Phoenix form field or a plain name/value pair.

The component renders a <textarea> element together with optional label, sublabel, description, helper text, and error messages. It supports a fixed-row layout (the default) and a content-aware autogrow mode that resizes the field as its value changes, starting at min_rows and growing without bound unless max_rows caps it.

Input vs Textarea vs Autocomplete vs Select

Fluxon offers several form controls for text-shaped values. Pick the one that matches the kind of value the user enters:

ComponentValue KindUse Case
<.input>A single line of free-form text or numberNames, emails, passwords, search, dates
<.textarea>Multi-line free-form textComments, descriptions, message bodies
<.autocomplete>One value chosen from a typed searchPicking from a long list while filtering
<.select>One value chosen from a fixed listStatus, category, country picker

Usage

Render a textarea by providing a name. A label is recommended so the field has a visible association for the user:

<.textarea name="comments" label="Comments" placeholder="Your thoughts..." />

Most fields combine a label with a placeholder, helper text, and an explicit row count:

<.textarea
  name="bio"
  label="Biography"
  description="A short paragraph that appears on your public profile."
  help_text="Markdown is supported."
  rows={5}
  placeholder="Tell us about yourself..."
/>

Sizes

The size attribute scales vertical/horizontal padding and font size. The default is "md":

<.textarea name="size_sm" size="sm" placeholder="Small" />
<.textarea name="size_md" size="md" placeholder="Medium (Default)" />
<.textarea name="size_lg" size="lg" placeholder="Large" />
<.textarea name="size_xl" size="xl" placeholder="Extra Large" />
SizeTextUse Case
smsmDense layouts: compact admin forms, side panels
mdsmDefault for most forms
lgbaseProminent text fields: support contact forms
xllgHigh-emphasis surfaces, single-field publishing UIs

Labels, Description, and Helper Text

The label area can carry up to three distinct strings:

  • label: the primary label rendered above the field.
  • sublabel: short inline text rendered next to the label, typically a state hint such as "(required)" or "(optional)".
  • description: longer guidance rendered between the label and the field.

Helper text rendered below the field uses the help_text attribute:

<.textarea
  name="release_notes"
  label="Release notes"
  sublabel="(required)"
  description="Summarize what changed in this release for end users."
  help_text="Aim for 3-5 short bullet points."
  rows={6}
/>

Form Integration

The component supports two binding modes: a Phoenix.HTML.FormField struct via field (changeset-driven forms) or a plain name (standalone fields).

Bind to a form field

When field is set, the component derives id, name, value, and errors from the form field struct. Errors are translated and rendered automatically, but only after the field has been touched (Phoenix.Component.used_input?/1):

<.form :let={f} for={@form} phx-change="validate" phx-submit="save">
  <.textarea field={f[:description]} label="Description" rows={6} />
</.form>

Standalone textarea

When you don't have a changeset, pass name, optionally value, and any error list directly:

<.textarea name="note" placeholder="Add a note..." value={@note} />
<.textarea name="reason" errors={["Reason is required."]} />

Picking the Binding Mode

Use field for changeset-backed forms (CRUD, validation, nested data). Use name for one-off fields without a changeset (feedback widgets, ad-hoc comment boxes, controls whose value is held in socket assigns).

States

Disabled

Disabled textareas cannot be focused or edited and render with reduced contrast. Disabling a parent <fieldset> cascades to descendant fields through HTML's native :disabled semantics:

<.textarea name="locked" value="Cannot change" disabled />

<fieldset disabled>
  <.textarea name="bio" value="..." />
</fieldset>

Errors

When the errors list is non-empty (or the bound form field has errors), the field renders in the danger color and each message is shown below the textarea:

<.textarea
  name="description"
  value="too short"
  errors={["Description must be at least 10 characters."]}
/>

When using field, errors are pulled from field.errors and translated through the configured Gettext backend.

Height and Resizing

By default, the field renders at a fixed rows height and the user can drag the native browser resize handle in the bottom-right corner to make it taller. Pass an explicit rows to set the initial height:

<.textarea name="comments" label="Comments" rows={6} />

Auto-growing height

Pass autogrow to make the field expand and shrink with its contents. By default the field grows without an upper bound; set max_rows to cap the height, after which content scrolls within the field. The native resize handle is disabled in this mode since the height is driven by content:

<.textarea
  name="message"
  label="Message"
  autogrow
  min_rows={2}
  max_rows={8}
  placeholder="Type your message..."
/>

Autogrow reacts to typing instantly on the client, with no LiveView round-trip or hook, and behaves consistently across every browser. The rows attribute is ignored when autogrow is enabled; min_rows sets the starting height so the field looks right before any value is entered. When max_rows is set, content beyond that height scrolls inside the field instead of expanding it further, with the scrollbar flush against the field's edge.

Constraining Field Width

By default, the field fills the width of its container. To narrow only the field while keeping the label, description, and helper text at their natural width, apply a width utility to any ancestor that targets [data-part=field-root]:

<div class="**:data-[part=field-root]:max-w-xs">
  <.textarea label="Notes" description="Brief notes only." name="notes" />
</div>

This pattern works uniformly across all Fluxon input-shaped form components.

Examples

Comment form bound to a changeset

<.form :let={f} for={@form} phx-change="validate" phx-submit="save">
  <.textarea
    field={f[:body]}
    label="Comment"
    placeholder="Share your thoughts..."
    rows={4}
    phx-debounce="blur"
  />
  <.button type="submit" color="primary">Post comment</.button>
</.form>

Chat composer that grows with the message

<.textarea
  name="message"
  label="Message"
  autogrow
  min_rows={1}
  max_rows={10}
  placeholder="Send a message..."
  phx-keydown="maybe_send"
  phx-key="Enter"
/>

Required field with sublabel and description

<.textarea
  field={@form[:summary]}
  label="Summary"
  sublabel="(required)"
  description="Used as the preview text wherever this post is linked."
  help_text="Keep it under 200 characters."
  rows={3}
  maxlength="200"
  required
/>

Constrained-width feedback widget

<div class="**:data-[part=field-root]:max-w-md">
  <.textarea
    name="feedback"
    label="How can we improve?"
    autogrow
    min_rows={3}
    max_rows={8}
  />
</div>

Summary

Components

Renders a labeled multi-line text input with support for sizes, autogrow, and form integration.

Components

textarea(assigns)

Renders a labeled multi-line text input with support for sizes, autogrow, and form integration.

Use this for any free-form multi-line value: comments, descriptions, message bodies, release notes, feedback. The component renders the <textarea> element plus its surrounding label, description, helper text, and error messages.

Pass a Phoenix.HTML.FormField via field to bind the textarea to a changeset-backed form, or pass name, value, and optionally errors directly for standalone use.

Attributes

  • id (:string) - Sets the textarea's id. When omitted, the component falls back to the value of name (or to field.id when field is set) so the rendered <label> can target the textarea via for.

    Defaults to nil.

  • field (Phoenix.HTML.FormField) - A Phoenix.HTML.FormField struct, typically obtained from a form binding such as f[:body]. When provided, the textarea derives its id, name, value, and errors from the struct, and runs error messages through the project's translation helper. Errors are only shown after the field has been touched, as reported by Phoenix.Component.used_input?/1.

  • class (:any) - Extra CSS classes applied to the underlying <textarea> element. Use this to adjust typography (for example font-mono), padding, or background without affecting the surrounding label and helper text.

    Defaults to nil.

  • help_text (:string) - Helper text rendered below the field. Use for tips, formatting hints, or follow-up instructions that are easier to read after the user has seen the textarea.

    Defaults to nil.

  • label (:string) - Primary label text rendered above the field. Associated with the textarea through the for attribute, using the textarea's id. When omitted, no <label> is rendered.

    Defaults to nil.

  • sublabel (:string) - Short inline hint rendered alongside the main label. Use for state cues such as "(required)" or "(optional)" that belong with the label rather than the field.

    Defaults to nil.

  • description (:string) - Longer guidance text rendered between the label and the field. Use for sentences that explain the field's purpose or set expectations about the value.

    Defaults to nil.

  • value (:string) - The current value of the textarea. Required when not using field. When field is set, this attribute is ignored in favor of field.value. Defaults to an empty string when neither value nor field provides one.

  • errors (:list) - A list of error message strings rendered below the field. When field is set, errors are pulled from field.errors and translated automatically; use this attribute to surface errors on standalone fields that are not bound to a form field.

    Defaults to [].

  • name (:string) - The submitted name for the textarea. Required when not using field. When field is set, this attribute is ignored in favor of field.name.

  • rows (:integer) - The number of visible text lines, mapped directly to the underlying <textarea rows> attribute. Ignored when autogrow is true, in which case min_rows is used as the fallback rows value for browsers without field-sizing support.

    Defaults to 3.

  • autogrow (:boolean) - When true, the field expands and shrinks to fit its content, starting at min_rows and growing without bound unless max_rows caps it. The native resize handle is disabled in this mode.

    Defaults to false.

  • min_rows (:integer) - Minimum number of visible rows when autogrow is enabled. Also used as the underlying <textarea rows> value so the field has a sensible initial height before any value is rendered.

    Defaults to 2.

  • max_rows (:integer) - Maximum number of visible rows when autogrow is enabled. When set, content beyond this height scrolls within the field. When omitted (the default), the field grows without an upper bound and never scrolls.

    Defaults to nil.

  • disabled (:boolean) - When true, the field cannot be focused or edited and renders with reduced contrast. Disabling a parent <fieldset> cascades through HTML's native :disabled semantics without setting this attribute on each textarea.

    Defaults to false.

  • size (:string) - Controls the field's vertical/horizontal padding and font size.

    • sm: Compact padding with sm text. Best for dense layouts and side panels.
    • md: Default padding with sm text. Suitable for most forms.
    • lg: Larger padding with base text. Good for prominent fields such as support contact forms.
    • xl: Largest padding with lg text. For high-emphasis surfaces and single-field publishing UIs.

    Defaults to "md".

    Defaults to "md". Must be one of "sm", "md", "lg", or "xl".

  • Global attributes are accepted. Any additional HTML attributes supported by <textarea>, forwarded as-is to the rendered element. Common values include placeholder, maxlength, minlength, required, readonly, spellcheck, and Phoenix bindings such as phx-change, phx-debounce, and phx-blur. Supports all globals plus: ["autocomplete", "cols", "dirname", "disabled", "form", "maxlength", "minlength", "name", "placeholder", "readonly", "required", "rows", "wrap", "spellcheck"].