Field
A form control with its label, hint and error: input, textarea, select, checkbox, radio or switch.
{ui field,
name: 'name',
label: 'Name',
placeholder: 'Ada Lovelace',
/}
The label is tied to the control by id, which is the name unless you pass one. Pass an id when the same name appears twice on a page. A plain field is an input; control picks another.
As it appears on your profile.
{ui field,
name: 'handle',
label: 'Handle',
hint: 'As it appears on your profile.',
/}
Use lowercase letters, numbers and dashes.
{ui field,
name: 'slug',
label: 'Slug',
value: 'Not A Slug',
error: 'Use lowercase letters, numbers and dashes.',
/}
An error replaces the hint, sets aria-invalid on the input and is announced as an alert. Both the hint and the error are linked to the input with aria-describedby, so a screen reader reads them with it.
Render the field again with the error from the server and swap it in place: the route returns the HTML, and there is nothing to validate in the browser.
<div class="flex flex-col gap-4">
{ui field, name: 'email', label: 'Email', type: 'email', required: true /}
{ui field, name: 'password', label: 'Password', type: 'password' /}
{ui field, name: 'locked', label: 'Locked', value: 'Read only for now', disabled: true /}
</div>
A file input styles its button to match, and a range is the native slider in the primary colour. Set min, max, step or accept through attrs.
<div class="flex flex-col gap-6">
{ui field,
name: 'avatar',
label: 'Avatar',
type: 'file',
attrs: ['accept' => 'image/*'],
/}
{ui field,
name: 'volume',
label: 'Volume',
type: 'range',
value: '6',
attrs: ['min' => 0, 'max' => 10],
/}
</div>
class and attrs go on the control, not the wrapper, so attrs: ['hx-post' => $url, 'hx-trigger' => 'change'] makes the control itself the HTMX element.
Other controls
A textarea takes the same params as an input. A select takes options as key and title pairs, value for the chosen key and an optional placeholder, which becomes an empty first option.
Shown on your profile.
{ui field,
control: 'textarea',
name: 'bio',
label: 'Bio',
placeholder: 'A few words about you',
hint: 'Shown on your profile.',
/}
{ui field,
control: 'select',
name: 'status',
label: 'Status',
options: ['draft' => 'Draft', 'review' => 'In review', 'live' => 'Live'],
value: 'review',
/}
A checkbox and a switch put the label beside the control and take checked. A radio is a group: options lists the choices, value is the chosen one and label is the group's legend. Each radio gets the id {id}-{key}.
<div class="flex flex-col gap-6">
{ui field,
control: 'checkbox',
name: 'terms',
label: 'Accept the terms',
/}
{ui field,
control: 'switch',
name: 'notify',
label: 'Email me about replies',
checked: true,
/}
{ui field,
control: 'radio',
name: 'plan',
label: 'Plan',
options: ['free' => 'Free', 'team' => 'Team', 'business' => 'Business'],
value: 'team',
/}
</div>
Params
| Param | Default | Description |
|---|---|---|
| control | 'input' | input, textarea, select, checkbox, radio or switch |
| name | '' | the control's name |
| id | $name | the control's id, the name by default |
| label | null | the label, above the control, or beside a checkbox and switch |
| type | 'text' | input only: any input type, e.g. email, password, file or range |
| value | '' | the current value; for a select or radio group, the chosen option's key; for a checkbox, what it submits, 1 by default |
| options | [] | select and radio: key => title pairs |
| checked | false | checkbox and switch: whether it is on |
| placeholder | null | hint text inside an empty input or textarea; for a select, an empty first option |
| hint | null | muted help text under the control |
| error | null | replaces the hint and marks the control invalid |
| required | false | sets the required attribute |
| disabled | false | sets the disabled attribute |
| class | '' | added to the control, not the wrapper |
| attrs | [] | attributes on the control, e.g. ['hx-post' => $url] |