Skua form components — button, label, error, field wrapper, input, textarea, toggle (checkbox / radio / switch), OTP, chip toggle, segmented control and slider (single + dual-handle range).
Every input accepts field={@form[:name]} as the primary API and falls back
to bare name/value. Errors surface only after the field is used, are
linked to the control with aria-describedby, and unchecked checkboxes emit
a hidden false companion so phx-change params never silently drop.
These components carry no JavaScript — they are real form elements styled
by assets/css/skua.css and driven entirely by server state.
Summary
Functions
A button.
A checkbox styled as a chip — for multi-pick chip groups. Real checkboxes, so they submit under one array name.
Inline error message(s) for a field. Rendered with an id so the control can
reference it via aria-describedby.
A labelled text input. Drive it with a form field
A field label. Pass for to associate it with a control id.
A segmented code / OTP input. A hidden <input> carries the combined value,
so phx-change/phx-submit work.
A single-select segmented control — real radio inputs, so it submits and
works with phx-change natively (no JavaScript).
A slider. Single-handle by default; pass range for a two-handle range
with independently draggable thumbs. Drag with the mouse/touch or operate with
the keyboard (←/→/↑/↓, PageUp/Down, Home/End); ARIA slider roles throughout.
Values post through hidden inputs so phx-change/submit work with no JS glue.
A labelled multi-line textarea. Same field API as input/1.
A checkbox, radio, or switch — a real, keyboard-operable form input with
a CSS-drawn visual that reacts to native :checked/:focus-visible (no JS).
Functions
A button.
<.button>Save</.button>
<.button variant="primary" type="submit">Create account</.button>
<.button variant="danger" phx-click="delete">Delete</.button>Attributes
variant(:string) - Defaults to"secondary". Must be one of"primary","secondary","ghost", or"danger".type(:string) - Defaults to"button".size(:string) - Defaults tonil.Must be one ofnil,"sm","md", or"lg".icon_only(:boolean) - square icon button; provide an aria-label. Defaults tofalse.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["disabled", "form", "name", "value", "aria-label"].
Slots
inner_block(required)
A checkbox styled as a chip — for multi-pick chip groups. Real checkboxes, so they submit under one array name.
<.chip_toggle :for={p <- @perms} field={@form[:perms]} value={p} label={p} />Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.name(:string) - Defaults tonil.value(:string) (required)checked(:boolean) - Defaults tonil.label(:string) - Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["disabled"].
Slots
inner_block
Inline error message(s) for a field. Rendered with an id so the control can
reference it via aria-describedby.
Attributes
id(:string) - Defaults tonil.errors(:list) - Defaults to[].
A labelled text input. Drive it with a form field:
<.input field={@form[:email]} type="email" label="Work email" required />or bare attributes:
<.input name="q" value={@q} placeholder="Search…" />Polymorphic, like CoreComponents.input/1: type="checkbox", "select"
(pass options), "textarea", and "hidden" render the matching Skua
control, so generated phx.gen.auth/phx.gen.live forms work unchanged and
look Skua-styled.
<.input field={@form[:role]} type="select" options={[{"Admin", "admin"}]} prompt="Pick…" />
<.input field={@form[:agree]} type="checkbox" label="I agree" />
<.input field={@form[:bio]} type="textarea" rows={4} label="Bio" />Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.type(:string) - Defaults to"text".label(:string) - Defaults tonil.placeholder(:string) - Defaults tonil.hint(:string) - Defaults tonil.errors(:list) - Defaults tonil.required(:boolean) - Defaults tofalse.checked(:boolean) - checkbox: explicit checked state. Defaults tonil.options(:list) - select: options (any Phoenix options_for_select format). Defaults to[].multiple(:boolean) - select: allow multiple. Defaults tofalse.prompt(:string) - select: leading empty prompt option. Defaults tonil.rows(:integer) - textarea: rows. Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["autocomplete", "inputmode", "min", "max", "step", "pattern", "readonly", "disabled"].
Slots
leading- icon/affix before the input.trailing- icon/affix after the input.
A field label. Pass for to associate it with a control id.
Attributes
for(:string) - Defaults tonil.required(:boolean) - Defaults tofalse.class(:any) - Defaults tonil.
Slots
inner_block(required)
A segmented code / OTP input. A hidden <input> carries the combined value,
so phx-change/phx-submit work.
<.otp_input field={@form[:code]} length={6} group={3} />Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.length(:integer) - Defaults to6.mode(:string) - Defaults to"numeric". Must be one of"numeric", or"text".group(:integer) - insert a separator every N cells. Defaults tonil.label(:string) - Defaults tonil.errors(:list) - Defaults tonil.
A single-select segmented control — real radio inputs, so it submits and
works with phx-change natively (no JavaScript).
<.segmented field={@form[:view]} options={["List", "Board", "Calendar"]} />
<.segmented field={@form[:plan]} options={[{"Monthly", "mo"}, {"Yearly", "yr"}]} label="Billing" />Options take any {label, value} / bare-value form, like select/1. The
selected segment comes from the field value (or an explicit value).
Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.options(:list) (required)label(:string) - Defaults tonil.errors(:list) - Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["disabled"].
A slider. Single-handle by default; pass range for a two-handle range
with independently draggable thumbs. Drag with the mouse/touch or operate with
the keyboard (←/→/↑/↓, PageUp/Down, Home/End); ARIA slider roles throughout.
Values post through hidden inputs so phx-change/submit work with no JS glue.
<.slider field={@form[:volume]} min={0} max={100} value={40} label="Volume" />
<.slider name="price" range value={[20, 80]} min={0} max={100} step={5} label="Price" />Single posts under name; range posts under name[min] / name[max].
Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - single: a number; range: a [lo, hi] list. Defaults tonil.min(:integer) - Defaults to0.max(:integer) - Defaults to100.step(:integer) - Defaults to1.range(:boolean) - Defaults tofalse.label(:string) - Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted.
A labelled multi-line textarea. Same field API as input/1.
Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.value(:any) - Defaults tonil.label(:string) - Defaults tonil.placeholder(:string) - Defaults tonil.hint(:string) - Defaults tonil.errors(:list) - Defaults tonil.required(:boolean) - Defaults tofalse.rows(:integer) - Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["readonly", "disabled", "maxlength", "minlength"].
A checkbox, radio, or switch — a real, keyboard-operable form input with
a CSS-drawn visual that reacts to native :checked/:focus-visible (no JS).
<.toggle type="switch" field={@form[:dark]} label="Dark mode" />
<.toggle type="checkbox" name="tos" label="I agree" />Checkboxes emit a hidden false companion so deselection is never dropped
from phx-change params.
Attributes
field(Phoenix.HTML.FormField) - Defaults tonil.id(:string) - Defaults tonil.name(:string) - Defaults tonil.type(:string) - Defaults to"checkbox". Must be one of"checkbox","radio", or"switch".value(:string) - the value submitted when checked. Defaults to"true".checked(:boolean) - Defaults tonil.label(:string) - Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted. Supports all globals plus:
["disabled", "required"].