Text Field
Self-contained label, input, and help/error text in one form-associated Web Component. Participates in native forms via ElementInternals and emits a composed change event.
Preview
<esa-text-field label="Full name" placeholder="Jane Doe" help-text="As it appears on the permit."></esa-text-field> Types
The type attribute maps straight to the native input type.
<esa-text-field label="Email" type="email" placeholder="you@example.com"></esa-text-field>
<esa-text-field label="Password" type="password"></esa-text-field>
<esa-text-field label="Count" type="number"></esa-text-field> Sizes
<esa-text-field label="Extra small" size="xs" placeholder="Extra small"></esa-text-field>
<esa-text-field label="Small" size="sm" placeholder="Small"></esa-text-field>
<esa-text-field label="Medium" size="md" placeholder="Medium"></esa-text-field>
<esa-text-field label="Large" size="lg" placeholder="Large"></esa-text-field> States
<esa-text-field label="Required" required placeholder="Cannot be empty"></esa-text-field>
<esa-text-field label="With error" error-text="This field is required." required></esa-text-field>
<esa-text-field label="Disabled" disabled value="Read only"></esa-text-field> Form participation
The element is form-associated. Submitting logs the FormData entry for contact.
<form>
<esa-text-field label="Contact" name="contact" placeholder="Type then submit"></esa-text-field>
<button type="submit">Submit</button>
</form> API
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | '' | Visible label rendered above the input. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Control size. |
placeholder | string | '' | Placeholder shown when empty. |
help-text | string | '' | Helper text shown below the input. Property: `helpText`. |
error-text | string | '' | Error message; replaces help text and turns the field red when present. Property: `errorText`. |
required | boolean | false | Marks the field required and renders an asterisk on the label. |
disabled | boolean | false | Disables interaction. |
name | string | undefined | — | Form field name — the key this control submits under. |
type | 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'text' | Native input type. |
value | string | '' | Current value; mirrored to the form on every input. |
prefix | string | '' | |
suffix | string | '' | |
pattern | string | '' | Regular expression the value must match — forwarded to the inner input. |
minlength | number | undefined | — | |
maxlength | number | undefined | — | |
autocomplete | string | '' | Autofill hint (`email`, `given-name`, `one-time-code`, …). This is the ONLY way to satisfy SC 1.3.5 Identify Input Purpose (AA): `type="email"` says what KIND of data the field wants, `autocomplete="email"` says WHOSE. It also turns on browser autofill, which is a large win for motor impairments. Use the real fixed values, not invented ones. |
inputmode | string | '' | Mobile keyboard hint (`numeric`, `decimal`, `tel`, …). Usability only — enforces nothing. |
live-error | boolean | false | Announce the error the moment it appears, instead of only when the field is focused. OFF by default, and that default is the considered one. The house pattern is validate-on-submit with an `<esa-error-summary>` that takes focus — under which a live region here would fire an assertive announcement for EVERY invalid field at once, racing the summary the user was just sent to. `aria-describedby` already carries the message when they arrive at the field. Turn it on for fields you validate INLINE (on blur), where the appearing message is the only signal and there is exactly one of it. Note that JAWS may then announce it twice — once live, once as the description on focus — which is the known cost of pairing a live region with `aria-describedby` on the same node. Property: `liveError`. |
Events
| Event | Type | Default | Description |
|---|---|---|---|
change | CustomEvent<{ value: string }> | — | Fired on every input. Composed and bubbling; detail.value is the current string. |
Binding these events from Angular
Every one of these is a CustomEvent, so the payload is on
$event.detail — $event.target.value reads empty, with no
error. The names are lowercase and Angular passes them to
addEventListener verbatim, so camel-casing one means it never fires.
(change)="onChange($event.detail)"
Accessibility
- Renders a native
<input>associated to its<label>viafor/id. - Sets
aria-invalid="true"whileerror-textis present. - The required asterisk carries an
aria-label="required". - Visible focus ring via
--focus-ring-*tokens.