SutraUI.Input (Sutra UI v0.3.0)

View Source

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

The unified form field component for Sutra UI. This is a drop-in replacement for Phoenix's generated input component, providing full parity with Phoenix generators while using Sutra UI styling.

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:

<.simple_form for={@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."
  />
  <:actions>
    <.button type="submit">Save</.button>
  </:actions>
</.simple_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"""
    <.simple_form for={@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."
      />
      <:actions>
        <.button type="submit">Create Account</.button>
      </:actions>
    </.simple_form>
    """
  end
end

Accessibility

  • Labels are properly associated with inputs via wrapping <label> elements
  • Description text is linked via aria-describedby on the input
  • aria-invalid is automatically set when errors are present
  • Error messages are displayed below inputs with destructive styling
  • Switch inputs include role="switch" and aria-checked
  • 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.