Field

A form control with its label, hint and error: input, textarea, select, checkbox, radio or switch.

Default
{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.

Hint

As it appears on your profile.

{ui field,
	name: 'handle',
	label: 'Handle',
	hint: 'As it appears on your profile.',
/}
Error
{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.

Types and states
<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.

File and range
<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.

Textarea

Shown on your profile.

{ui field,
	control: 'textarea',
	name: 'bio',
	label: 'Bio',
	placeholder: 'A few words about you',
	hint: 'Shown on your profile.',
/}
Select
{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}.

Checkbox, switch and radio
Plan
<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]