Patterns
Form validation
When to check a field, how to word the message, and how to build an error summary that actually gets a person back to the problem.
When to validate
Timing matters more than styling. Validating too early is the most common way to make a form feel hostile — a field that turns red while someone is still typing their email is telling them they are wrong before they have finished being right.
| Moment | Do | Why |
|---|---|---|
| While typing, before the field has ever been valid | Nothing | Every partially typed value is invalid. Flagging it is noise. |
| On blur, after the person leaves the field | Validate and show the error | They have finished their attempt; now feedback is useful. |
| While typing, after an error is showing | Re-validate and clear it as soon as it is fixed | Confirms the fix immediately, without waiting for another blur. |
| On submit | Validate everything, show the summary, move focus to it | The last chance to catch fields never visited. |
| Live constraints (password rules, character counts) | Show progress, not failure | A checklist filling in reads as help; a red border reads as blame. |
Field-level errors
The error sits directly below the field, linked with
aria-describedby, and the field is marked
aria-invalid="true". Three visual signals carry the state:
the 2px border, the circled exclamation, and the message.
Enter an email address in the format name@example.com
<div class="tmt-field tmt-field--invalid">
<label class="tmt-label" for="email">Email address</label>
<input class="tmt-input" id="email" type="email"
aria-invalid="true"
aria-describedby="email-error email-help">
<p class="tmt-help" id="email-help">We use this to send security alerts.</p>
<p class="tmt-error-text" id="email-error">
Enter an email address in the format name@example.com
</p>
</div>
aria-describedby takes a space-separated list, so a field
can keep its help text and gain an error. Put the error id first — it is the more urgent
of the two.
The error summary
On any form longer than about three fields, a summary at the top is what makes submission failures recoverable. Without it, a person whose screen shows the bottom of a long form gets no indication that anything happened at all.
<div class="tmt-alert tmt-alert--error" role="alert" tabindex="-1" id="error-summary">
<span class="tmt-alert__icon" aria-hidden="true">✕</span>
<div class="tmt-alert__content">
<p class="tmt-alert__title">There are 2 problems with this form</p>
<ul>
<li><a href="#email">Enter an email address in the format name@example.com</a></li>
<li><a href="#device-name">Enter a name for this device</a></li>
</ul>
</div>
</div>
Four rules make the summary work:
- Move focus to it on failed submit. It carries
tabindex="-1"so it can receive focus programmatically without entering the tab order. - Every item is a link to the field's
id. Following it puts the cursor in the field that needs fixing. - The link text is the error message, not the field name. It is the same sentence that appears beside the field, so the person is not translating between two wordings.
- List them in the order they appear in the form.
Update the page title too — prefixing it with "Error: " tells someone who has switched tabs that the submission failed.
Wording
Start with a verb and say what to do. Do not describe what the person did wrong.
| Not | Write |
|---|---|
| Invalid email | Enter an email address in the format name@example.com |
| This field is required | Enter a name for this device |
| Password too weak | Use at least 12 characters |
| Date is not valid | Enter a date in the future, such as 10 September 2026 |
| Error 422: unprocessable entity | We could not save this device. Try again, or contact support with reference 422. |
Say how many problems there are in the summary title — "There are 2 problems with this form" — and use the singular when there is one. It sets expectations before the person starts reading.
After a successful submit
- Confirm it. A form that just closes leaves people unsure whether it worked.
- If the page navigates, put a success alert at the top of the destination and move focus to the new page's heading.
- If it stays, use a
role="status"alert and move focus to it. - Say what happens next: "Saved. Your schedule runs from tomorrow."
Native validation
Use the HTML attributes — required,
type, min,
max, pattern. They give you
free client-side checking and they inform assistive technology about the field's
constraints even before anything is submitted.
Then add novalidate on the form and take over the display.
The browser's own bubbles cannot be styled, disappear on their own, are inconsistent
across browsers, and are not translated into Arabic reliably. Keep the attributes for
their semantics; render the messages yourself.
In Arabic
- Error messages are translated properly, not machine-rendered from English. They are the sentences people read when they are already frustrated.
- The error icon sits on the inline-start edge and moves with the direction — no change needed.
- Format examples inside a message stay left-to-right. Wrap
name@example.comin<span dir="ltr">or the "@" and the dots land in the wrong places. - Never size a field or a message container to fit exactly one language's text.