Input
The custom element is <hui-input>.
Overview
A form-associated single-line text control. The native input lives in the shadow root and the host submits the value through ElementInternals, so it serialises with the enclosing form exactly as a native input would.
Example
Source
<hui-input name="name" placeholder="Name" aria-label="Name"></hui-input><hui-input name="email" type="email" value="ada@example.com" aria-label="Email"></hui-input>The Go template that renders it:
{{ range .Fields }} <hui-input name="{{ .Name }}" type="{{ .Type }}" value="{{ .Value }}" placeholder="{{ .Placeholder }}" aria-label="{{ .Label }}"></hui-input>{{ end }}API
Attributes14
| Name | Type | Default | Description |
|---|---|---|---|
name | string | '' | The form field name. With no name the control contributes no entry to FormData. |
disabled | boolean | false | Disables the control and clears its form value. |
type | "text" | "email" | "password" | "search" | "tel" | "url" | "number" | "date" | "time" | "datetime-local" | "month" | "week" | "text" | The input kind. An unknown value is normalised back to text in willUpdate. |
value | string | '' | The current value. Not reflected; the attribute only seeds the value restored by a form reset. |
placeholder | string | '' | Placeholder text, forwarded to the native input when non-empty. |
readonly | boolean | false | Makes the internal input read-only. |
required | boolean | false | Marks the control required and forwards constraint validity to the form. |
minlength | number | - | Minimum length, forwarded to the native input. Omitted when unset. |
maxlength | number | - | Maximum length, forwarded to the native input. Omitted when unset. |
pattern | string | - | A validation pattern, forwarded to the native input. Omitted when unset. |
autocomplete | string | - | An autocomplete hint, forwarded to the native input. Omitted when unset. |
min | string | - | Minimum value for numeric and date types. Omitted when unset. |
max | string | - | Maximum value for numeric and date types. Omitted when unset. |
step | string | - | Stepping interval for numeric and date types. Omitted when unset. |
Properties14
| Name | Type | Default | Description |
|---|---|---|---|
name | string | '' | Reflects to the name attribute. |
disabled | boolean | false | Reflects to the disabled attribute. |
type | InputType | 'text' | Reflects to the type attribute. |
value | string | '' | The current value. Not reflected; changing it commits the new value to the form. |
placeholder | string | '' | Reflects to the placeholder attribute. |
readonly | boolean | false | Reflects to the readonly attribute. |
required | boolean | false | Reflects to the required attribute. |
minlength | number | - | Reflects to the minlength attribute. |
maxlength | number | - | Reflects to the maxlength attribute. |
pattern | string | - | Reflects to the pattern attribute. |
autocomplete | string | - | Reflects to the autocomplete attribute. |
min | string | - | Reflects to the min attribute. |
max | string | - | Reflects to the max attribute. |
step | string | - | Reflects to the step attribute. |
Events2
| Name | Description |
|---|---|
input | Emitted from the host on every keystroke, after the value and validity update. bubbles and composed; no detail. The internal input event is stopped at the shadow boundary. |
change | Emitted from the host when the native change fires. bubbles and composed; no detail. |
CSS custom properties6
| Name | Default | Description |
|---|---|---|
--hui-background | oklch(1 0 0) | Field fill. |
--hui-input | oklch(0.62 0.019 323.02) | Border colour of the control boundary. |
--hui-radius | 0.45rem | Base radius; the field uses --hui-radius-lg. |
--hui-muted | oklch(0.96 0.003 325.6) | Fill while readonly. |
--hui-destructive | oklch(0.56 0.245 27.325) | Border colour while aria-invalid="true". |
--hui-focus-ring-width | 3px | Width of the keyboard focus ring. |
::part() hooks2
| Name | Description |
|---|---|
input | The internal native <input>. |
control | The same element; the control carries both part names. |
States
Types
type is passed straight to the native input, so password, number and date keep the platform's own editing, keyboard and validation.
Source
<hui-input name="pin" type="password" value="secret" aria-label="PIN"></hui-input><hui-input name="count" type="number" min="0" max="10" value="3" aria-label="Count"></hui-input><hui-input name="due" type="date" value="2024-02-15" aria-label="Due date"></hui-input>Disabled and read-only
The difference between the two: a disabled field is skipped by the keyboard and submits nothing, while a read-only one is still focusable and still submits its value.
Source
<hui-input name="locked" value="nope" disabled aria-label="Locked"></hui-input><hui-input name="readonly" value="fixed" readonly aria-label="Read only"></hui-input>Invalid
What a failed constraint looks like: aria-invalid="true" on a value the pattern rejects. The server decides when to set it; the element draws it.
Source
<hui-input name="code" pattern="[0-9]{3}" required value="ab" aria-invalid="true" aria-label="Code"></hui-input>Server-side mechanics
The server owns the field: it renders name, type, value, placeholder, required, pattern, min/max/step, minlength/maxlength, autocomplete, readonly and disabled, and the value submits under name through ElementInternals. Because value is not reflected, a swap must re-send the value attribute to seed the control, and a swap during typing replaces the element and loses the in-progress text and focus. Server-rendered validation is carried by required and pattern, which forward constraint validity, and by aria-invalid="true" or a hui-field invalid wrapper, which only paints the destructive border and ring.
Accessibility
- The accessible name comes from an
aria-labelor from ahui-fieldlabel; IDREF attributes cannot cross the shadow boundary, sohui-fieldsetsaria-labelandaria-descriptioninstead. - The four forwarded attributes,
aria-label,aria-description,aria-invalidandaria-required, are mirrored onto the internal input as they change. - An unknown or unsupported
typesilently renders astext; a control asking for a checkbox or a file is not this element. - Focus is shown with the shared ring on
:focus-visibleonly; an invalid control swaps the ring and border to--hui-destructive.
Keyboard
| Keys | Action |
|---|---|
Tab, Shift+Tab | Moves focus to and from the control. |
Standard editing keys | Arrows, Home, End, Backspace and selection behave exactly as the native input does. |
Number and date types | Arrow keys step the value, following the browser behaviour for that input type. |
Gotchas
- An unknown
typeis normalised totext, and that includescheckbox,radioandfile, none of which this element renders. valueis not reflected, so reading the attribute after typing returns the seed, not the current text.