Accessibility
A red border tells a sighted mouse user something is wrong. It tells a screen reader user nothing at all. Since 3.0 every error this plugin shows is also reported as text, associated with the field it belongs to.
There is nothing to enable. The only related option is focusOnError, which is already true.
What the plugin emits
| Feature | Behaviour |
|---|---|
aria-invalid | Set to "true" on a failing field, in both inline and summary modes. Removed — not set to "false" — once the field passes, so an unvalidated field makes no claim either way. |
aria-describedby | Points the field at the element holding its message, so a screen reader reads the reason when the field is focused. |
aria-live="polite" | On inline messages, so an error appearing on blur is announced without interrupting what the visitor is typing next. |
role="alert" | On the error summary. |
| Focus management | On a failed submit, focus moves to the summary, or to the first invalid field in inline mode. |
aria-busy | On a field while an asynchronous check is in flight. |
| Reduced motion | Help-text fades are skipped when the visitor has asked for reduced motion. |
Your aria-describedby is preserved
Fields often already point at hint text. The plugin appends its own token rather than replacing what is there, and on cleanup removes only the token it added.
<label for="pw">Password</label>
<span id="pw-hint">At least 12 characters.</span>
<input id="pw" type="password" aria-describedby="pw-hint"
data-validation="strength"><!-- While invalid -->
<input id="pw" aria-describedby="pw-hint jfv-error-pw-1" aria-invalid="true">
<!-- Once corrected — your hint survives -->
<input id="pw" aria-describedby="pw-hint">The error summary
With errorMessagePosition: 'top' the plugin renders one summary above the form.
It is a role="alert", receives focus on a failed submit, and every entry is a link
to the field it describes — so the summary can be navigated by keyboard, not merely read.
$.validate({
errorMessagePosition: 'top'
});<div class="form-error alert alert-danger" role="alert" tabindex="-1">
<strong>Form submission failed!</strong>
<ul>
<li><a href="#email">You have not given a correct e-mail address</a></li>
<li><a href="#jfv-field-age-1">The input value is shorter than 2 characters</a></li>
</ul>
</div>
Fields without an id are given a generated one so the link has somewhere to point.
That is what {id} means in
the summary template.
When a failed submit produces several errors at once, one focusable list is far easier to work through than hunting for messages scattered down the page. It is also the pattern most assistive technology users will recognise.
What the theme handles
The bundled stylesheet was corrected in 3.0 to meet WCAG 2.2 AA:
- Contrast. Error text is
#843534, which clears 4.5:1 against the summary background. The previous#b94a48managed only 3.93:1. - Not colour alone. Invalid fields carry an icon as well as a red border, and inline messages are prefixed with a warning marker — WCAG 1.4.1.
- Target size. Summary links are at least 24 px tall — WCAG 2.2 SC 2.5.8.
- Reduced motion. Transitions and animations are disabled when the visitor has asked for that.
It reports errors accessibly, but it cannot invent a <label> you did not write. Every field still needs one, associated by for/id or by wrapping. That is the single most common form accessibility failure and it is outside what any validation library can fix.
Working with the browser
novalidate is added to the form by default, so the browser does not stack its own
error bubbles on top of the plugin's messages. A novalidate attribute you wrote
yourself is never removed.
Loading the native module mirrors every
result onto the element, which means :user-invalid and
form.checkValidity() agree with your rules — useful if your CSS already styles
those states.
$.validate({
modules: 'native',
novalidate: true // the default
});Using the helpers yourself
If you take over error display with
inlineErrorMessageCallback,
the ARIA wiring is available so your own markup can behave the same way.
$.validate({
inlineErrorMessageCallback: function ($input, errorMsg, conf) {
var $slot = $input.closest('.field').find('.field-error');
if (errorMsg) {
$slot.text(errorMsg);
$.formUtils.a11y.describeError($input, $slot);
} else {
$.formUtils.a11y.clearError($input);
}
return false; // we rendered it ourselves
}
});Testing your forms
Automated checks catch some of this. These are the parts worth doing by hand:
- Keyboard only. Submit an empty form. Focus should land on the summary, and each entry should take you to its field.
- Screen reader. With NVDA, JAWS or VoiceOver, confirm the error is announced on blur, and that focusing a failed field re-reads the reason.
- Zoom and reflow. At 200% zoom and 320 px width, messages should stay attached to their fields.
- Colour. Turn on a greyscale filter. Every error should still be identifiable.
The bundled theme and the markup the plugin emits were checked with axe-core against the project's own test forms, in both inline and summary modes, with zero violations attributable to the plugin. Your own markup — labels, headings, landmarks — is still yours to get right.