SutraUI.Input (Sutra UI v0.4.0)
View SourceRenders 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:
Automatic - from a
Phoenix.HTML.FormField(Ecto changeset errors):<.input field={@form[:email]} type="email" label="Email" />Manual - via the
errorsattribute:<.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 toSutraUI.Checkboxwith hidden false valuetype="switch"- Delegates toSutraUI.Switch(toggle with role="switch")type="select"- Renders a native<select>elementtype="textarea"- Delegates toSutraUI.Textareatype="range"- Delegates toSutraUI.Sliderwith colocated hooktype="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
endAccessibility
- Labels are properly associated with inputs via wrapping
<label>elements - Description and error text are linked via
aria-describedbywhen an input id is available aria-invalidis 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
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 tonil.name(:any) - The name attribute for the input. Defaults tonil.label(:string) - Label text - renders label before input. Defaults tonil.description(:string) - Helper text rendered below the label, above the input. Defaults tonil.value(:any) - The value of the input. Defaults tonil.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 tonil.options(:list) - The options to pass to Phoenix.HTML.Form.options_for_select/2.multiple(:boolean) - The multiple flag for select inputs. Defaults tofalse.class(:any) - Additional CSS classes. Defaults tonil.- 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"].
Translates an error message using gettext.
Translates the errors for a field from a keyword list of errors.