SutraUI.Input (Sutra UI v0.4.0)

View Source

Renders form input elements with label, description, and error handling.

The unified form field component for Sutra UI. It covers the common Phoenix generator input patterns while using Sutra UI styling, and delegates richer controls to the focused Sutra UI components.

Basic Usage

# Simple text input
<.input type="text" name="username" placeholder="Username" />

# With label
<.input type="email" name="email" label="Email" placeholder="you@example.com" />

# With label and description
<.input
  type="text"
  name="username"
  label="Username"
  description="This will be your public display name."
  placeholder="johndoe"
/>

Phoenix Form Integration

Pass a Phoenix.HTML.FormField via the field attribute to automatically extract the input's id, name, value, and validation errors:

<.form for={@form} class="form" phx-submit="save">
  <.input field={@form[:email]} type="email" label="Email" />
  <.input field={@form[:password]} type="password" label="Password" />
  <.input
    field={@form[:bio]}
    type="textarea"
    label="Bio"
    description="Tell us about yourself."
  />
  <div class="flex justify-end">
    <.button type="submit">Save</.button>
  </div>
</.form>

Errors are displayed automatically when the field has been interacted with (via Phoenix.Component.used_input?/1), so errors won't flash on first render.

Error Handling

Errors can come from two sources:

  1. Automatic - from a Phoenix.HTML.FormField (Ecto changeset errors):

     <.input field={@form[:email]} type="email" label="Email" />
  2. Manual - via the errors attribute:

     <.input name="email" errors={["can't be blank"]} />

When errors are present, the input gets aria-invalid="true" and error messages render below the input with a destructive icon.

Input Types

This component handles all standard HTML input types, with special handling for:

  • type="checkbox" - Delegates to SutraUI.Checkbox with hidden false value
  • type="switch" - Delegates to SutraUI.Switch (toggle with role="switch")
  • type="select" - Renders a native <select> element
  • type="textarea" - Delegates to SutraUI.Textarea
  • type="range" - Delegates to SutraUI.Slider with colocated hook
  • type="hidden" - Renders just the input, no wrapper or label

Type Examples

# Select with options
<.input
  type="select"
  name="country"
  label="Country"
  prompt="Select a country"
  options={[{"United States", "us"}, {"Canada", "ca"}]}
/>

# Checkbox
<.input type="checkbox" name="terms" label="I agree to the terms" />

# Switch (toggle)
<.input type="switch" name="notifications" label="Enable notifications" />

# Textarea
<.input type="textarea" name="bio" label="Bio" rows={4} />

# Range slider
<.input type="range" name="volume" label="Volume" min={0} max={100} />

Select Types

This component provides two ways to render select inputs:

Native Select (via <.input type="select">)

For standard form selects that work with Phoenix generators:

<.input
  field={@form[:country]}
  type="select"
  label="Country"
  prompt="Select a country"
  options={[{"United States", "us"}, {"Canada", "ca"}]}
/>

Custom Select (via SutraUI.Select)

For advanced features like search/filter, keyboard navigation, and custom styling, use the dedicated SutraUI.Select component directly:

<.select id="country" name="country" value={@country} searchable>
  <.select_option value="us" label="United States" />
  <.select_option value="ca" label="Canada" />
</.select>

See SutraUI.Select for more details.

Complete Form Example

Here is a realistic registration form demonstrating labels, descriptions, error handling, and multiple input types working together:

defmodule MyAppWeb.RegistrationLive do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    changeset = Accounts.change_user(%User{})
    {:ok, assign(socket, form: to_form(changeset))}
  end

  def handle_event("validate", %{"user" => params}, socket) do
    changeset =
      %User{}
      |> Accounts.change_user(params)
      |> Map.put(:action, :validate)

    {:noreply, assign(socket, form: to_form(changeset))}
  end

  def handle_event("save", %{"user" => params}, socket) do
    case Accounts.create_user(params) do
      {:ok, _user} -> {:noreply, push_navigate(socket, to: ~p"/dashboard")}
      {:error, changeset} -> {:noreply, assign(socket, form: to_form(changeset))}
    end
  end

  def render(assigns) do
    ~H"""
    <.form for={@form} class="form" phx-change="validate" phx-submit="save">
      <.input
        field={@form[:name]}
        label="Full Name"
        placeholder="Jane Smith"
      />
      <.input
        field={@form[:email]}
        type="email"
        label="Email"
        description="We'll send a confirmation link to this address."
        placeholder="jane@example.com"
      />
      <.input
        field={@form[:password]}
        type="password"
        label="Password"
        description="Must be at least 8 characters."
        placeholder="Create a password"
      />
      <.input
        field={@form[:role]}
        type="select"
        label="Role"
        prompt="Choose a role"
        options={[{"Developer", "dev"}, {"Designer", "design"}, {"Manager", "pm"}]}
      />
      <.input
        field={@form[:bio]}
        type="textarea"
        label="Bio"
        description="Brief description for your profile."
        rows={3}
      />
      <.input
        field={@form[:terms]}
        type="checkbox"
        label="I agree to the terms of service"
      />
      <.input
        field={@form[:newsletter]}
        type="switch"
        label="Subscribe to newsletter"
        description="Receive weekly updates about new features."
      />
      <div class="flex justify-end">
        <.button type="submit">Create Account</.button>
      </div>
    </.form>
    """
  end
end

Accessibility

  • Labels are properly associated with inputs via wrapping <label> elements
  • Description and error text are linked via aria-describedby when an input id is available
  • aria-invalid is automatically set when errors are present
  • Error messages are displayed below inputs with destructive styling
  • Switch inputs include role="switch" and use native checkbox checked state
  • Range inputs include aria-valuemin, aria-valuemax, aria-valuenow
  • Supports standard ARIA attributes via :rest

Summary

Functions

Renders an input with label, description, and error messages.

Translates an error message using gettext.

Translates the errors for a field from a keyword list of errors.

Functions

input(assigns)

Renders an input with label, description, and error messages.

A Phoenix.HTML.FormField may be passed as argument, which is used to retrieve the input name, id, and values. Otherwise all attributes may be passed explicitly.

Examples

<.input field={@form[:email]} type="email" label="Email" />
<.input name="my-input" errors={["oh no!"]} />
<.input field={@form[:username]} label="Username" description="Pick something unique." />

Attributes

  • id (:any) - The id attribute for the input. Defaults to nil.
  • name (:any) - The name attribute for the input. Defaults to nil.
  • label (:string) - Label text - renders label before input. Defaults to nil.
  • description (:string) - Helper text rendered below the label, above the input. Defaults to nil.
  • value (:any) - The value of the input. Defaults to nil.
  • type (:string) - Defaults to "text". Must be one of "checkbox", "color", "date", "datetime-local", "email", "file", "hidden", "month", "number", "password", "range", "search", "select", "switch", "tel", "text", "textarea", "time", "url", or "week".
  • field (Phoenix.HTML.FormField) - A form field struct retrieved from the form, for example: @form[:email].
  • errors (:list) - List of error messages to display. Defaults to [].
  • checked (:boolean) - The checked flag for checkbox inputs.
  • prompt (:string) - The prompt for select inputs. Defaults to nil.
  • options (:list) - The options to pass to Phoenix.HTML.Form.options_for_select/2.
  • multiple (:boolean) - The multiple flag for select inputs. Defaults to false.
  • class (:any) - Additional CSS classes. Defaults to nil.
  • Global attributes are accepted. Supports all globals plus: ["accept", "autocomplete", "capture", "cols", "disabled", "form", "list", "max", "maxlength", "min", "minlength", "multiple", "pattern", "placeholder", "readonly", "required", "rows", "size", "step", "phx-debounce", "phx-mounted", "aria-label", "aria-describedby", "aria-invalid", "aria-required"].

translate_error(arg)

Translates an error message using gettext.

translate_errors(errors, field)

Translates the errors for a field from a keyword list of errors.