Pattern
Form Validation Requires JS
Conventions for inline error messages, summary banners, and submit-button state. Browser-native HTML5 validation does most of the work; this pattern documents how to wire the rest.
About
Overview
Form validation is a pattern, not a component — it's how Field, Banner, Button and Toast cooperate when a form is wrong or submitted. Use HTML5 attributes (required, type, pattern, min, max) for client-side; show server-side errors via setError() on each Field.
Live
Demo
<form novalidate>
<ren-field>
<label>Email</label>
<input type="email" required>
</ren-field>
<button type="submit">Save</button>
</form>Patterns
Pieces
- HTML5 attributes:
required,type="email",pattern,min,max,minlength,maxlength. - Per-field errors: Form Field shows
aria-invalid+ the error message. - Form-level summary: a Banner at the top with the count of errors and links to each one (skip-to-error pattern).
- Server-side errors: after a failed submit, call
field.setError(message)for each invalid field. - Submit button state:
data-loadingwhile submitting; disabled until the form has any input on touch (don't disable proactively before the user types — it's confusing).
Variant
Multi-step forms
Use a multi-step form when a single page would feel overwhelming or when steps depend on previous answers. ren-form supports multi-step via the data-steps attribute on the host and a .ren-stepper progress indicator.
- Account
- 2Profile
- 3Plan
Step 2 of 3 — current step content goes here.
<ren-form data-steps="3">
<ol class="ren-stepper" aria-label="Setup progress">
<li data-completed>Account</li>
<li aria-current="step">Profile</li>
<li>Plan</li>
</ol>
<fieldset data-step="1">…</fieldset>
<fieldset data-step="2" data-active>…</fieldset>
<fieldset data-step="3">…</fieldset>
</ren-form>Stepper API
| Class / attribute | Effect |
|---|---|
.ren-stepper | The progress indicator. Numbered ol with completed / current / pending states. |
[aria-current="step"] | Marks the active step. |
[data-completed] | Marks a past step (checkmark fill). |
[data-steps="N"] on host | Declares the total number of steps. |
[data-active] on fieldset | Marks the currently visible step; others are hidden. |
Pattern checklist
- Validate the current step before Next advances.
- Allow free Back navigation — don't lose prior data.
- Save progress to
localStorageor the server so the user can leave and resume. - Last step is "Review" — show all entered data before final submit.
- Autofocus the first input on each step change.
- Announce progress via a polite live region: "Step 2 of 3."
Status of .ren-stepper: the stepper is an internal CSS pattern of ren-form, not a standalone component. There is no ren-stepper primitive, Web Component, or separate JS — it's a styled <ol> that consumer code drives. If you need a reusable Stepper outside a multi-step form (e.g. an onboarding tour, or a wizard not tied to a single form), open an issue — it's on the backlog.
Inclusive by default
Accessibility
- Use
novalidateon the form so you control validation timing instead of letting the browser show its own popup before submission. - Validate on blur (not on every keystroke) for first-time entry; revalidate on input after the field has been marked invalid once.
- Move focus to the first invalid field after a failed submit.
- Summary banner uses
role="alert"so screen readers announce the error count immediately. - For multi-step flows: each step is its own
<fieldset>with its own focus management; the stepper usesaria-current="step"on the active item.