form-field

Accessible form field web component with label, input, validation timing, custom error messages, and error summaries. Progressive enhancement from CSS-only validation to full JS coordination.

Attributes

Attribute Values Default Description
data-type checkbox, radio, file - Special styling for non-text inputs
data-no-icon boolean - Disable validation status icons
data-required boolean - Visual indicator (auto-detected from input)
data-valid boolean - Force valid state styling
data-invalid boolean - Force invalid state styling

Input Attributes (for JS enhancements)

Attribute Values Default Description
data-type (on input) otp, pin - Enable OTP/PIN multi-box enhancement
data-length (on input) 4, 6, 8 6 Number of digits for OTP/PIN input

Element Structure

The form-field element groups a label, input control, and optional validation message.

Child Element Purpose Key Attributes
<label> Accessible field label for (matches input id)
<input> / <textarea> / <select> Form control id, name, validation attrs, aria-describedby
<output> Validation/help message id, for, aria-live="polite"

Input Types

Works with all standard form controls: text, email, password, textarea, and select.

Password Toggle

Password inputs are automatically enhanced with a show/hide toggle button when JavaScript is available. No extra markup needed.

  • Appears automatically when JavaScript loads
  • Uses aria-pressed and aria-label for accessibility
  • Positions adjust alongside validation icons

Validation Status Icons

Form fields automatically display a checkmark (valid) or X (invalid) after user interaction. Icons are positioned inside the input's padding. Use data-no-icon to disable them.

OTP/PIN Input

Use data-type="otp" on the input for verification codes. Progressive enhancement: works as a standard text input without JS, enhances to multi-box with JS.

  • Auto-focus moves to the next box after entering a digit
  • Backspace moves focus to the previous box
  • Arrow keys navigate between boxes
  • Paste support fills multiple boxes at once

Output Message Classes

Use class="hint" and class="error" on output elements for different message types.

Class Visibility Use Case
.hint Always visible (hides when valid) Format requirements, help text
.error Only when invalid Error messages

Checkbox and Radio

Use data-type="checkbox" or data-type="radio" for inline label+input layout. Wrap radio groups in a <fieldset> with a <legend>.

CSS-Only Validation

Uses :user-valid and :user-invalid pseudo-classes to show validation states only after user interaction, preventing premature error states on page load.

JS-Enhanced Validation

Add data-validate to a <form> to enable features CSS can't handle: custom error messages, cross-field validation, checkbox group constraints, and error summaries. Without it, everything works as pure CSS validation.

Form Attributes

Attribute On Description
data-validate <form> Opt-in. No value = field-level errors (+ summary if present). "summary" = summary only.
data-submit <form> Submit mode: "native" (default), "event" (dispatches vb:submit), "fetch" (async with loading/success/error states).

Custom Error Message Attributes

Attribute names map directly to ValidityState keys. Place these on the input element.

Attribute ValidityState Key When Triggered
data-message-valuemissing valueMissing required field is empty
data-message-typemismatch typeMismatch type="email" / type="url" format wrong
data-message-patternmismatch patternMismatch pattern regex fails
data-message-tooshort tooShort Below minlength
data-message-toolong tooLong Above maxlength
data-message-rangeunderflow rangeUnderflow Below min
data-message-rangeoverflow rangeOverflow Above max
data-message-stepmismatch stepMismatch Not on step interval

Cross-Field and Group Attributes

Attribute On Description
data-match input ID of field that must have the same value
data-message-match input Custom message when data-match fails
data-min-checked fieldset Minimum number of checked checkboxes
data-max-checked fieldset Maximum number of checked checkboxes

Web Component API

<form-field> upgrades to a web component when JS loads. It provides these methods for programmatic use:

Method / Property Returns Description
validate() boolean Validate the field and update visual state. Returns validity.
setError(message) - Set a programmatic error (e.g. from server validation).
clearError() - Clear a programmatic error and reset state.
fieldName string Human-readable field name from the label.
input HTMLElement The controlled input element.

Error Summary

Add an <output class="error-summary"> inside your form for a consolidated list of all errors on submit.

Mode Attribute Behavior
Field-level only data-validate (no summary output) Errors appear inline next to each field
Summary only data-validate="summary" Summary at top, field-level errors hidden
Both data-validate + summary output present Summary at top AND inline errors on each field

Complete Contact Form

Why Use <output> for Messages?

  • Purpose-built: Represents the result of a calculation or user action
  • Native association: Has for attribute to link to input(s)
  • Accessible: Works naturally with aria-live for screen readers
  • No JavaScript required: Can show different states via CSS

Accessibility Checklist

  • Every <input> has a <label> with matching for/id
  • Required fields use the required attribute
  • Validation messages use <output> with aria-live="polite"
  • Inputs link to messages via aria-describedby
  • Form controls have appropriate autocomplete values
  • Error states don't rely on color alone (include text)

Related