HTML Form Validation: Getting Accessibility Right
HTML5 introduced native form validation attributes that make basic client-side validation straightforward. Add required, set type="email", throw in a pattern attribute, and browsers handle the validation automatically. It works, but the accessibility of that default implementation leaves significant gaps that many developers don’t notice or address.
The most obvious problem is that browser-native validation error messages appear as tooltips on focus. Visually, this can work fine—a message appears near the invalid field when you try to submit. But for screen reader users, that tooltip often isn’t announced at all, or is announced poorly depending on the browser and assistive technology combination.
I tested the same form with native HTML validation across different browser/screen reader pairings. Chrome with NVDA announced some errors inconsistently. Firefox with JAWS did better but still missed errors in some cases. Safari with VoiceOver on iOS had its own quirks. There’s no consistent, reliable behavior you can count on.
The HTML specification includes aria-invalid and aria-describedby as mechanisms for making validation errors accessible. But browsers don’t automatically set these attributes when native validation fails—you have to add that yourself with JavaScript. At which point, you’re writing custom validation code anyway, undermining the simplicity that native validation supposedly provided.
The timing of when validation occurs also creates accessibility issues. Native validation only runs on form submission, so users can fill out an entire form incorrectly and not discover the errors until they submit. For complex forms, this means potentially going back to fix multiple fields scattered throughout the form based on error messages that might not be clearly associated with their fields.
A better pattern is inline validation as users complete each field, providing immediate feedback. You can’t do this with native HTML validation alone—you need JavaScript to check field validity onBlur or onChange and display associated error messages. This requires reimplementing much of what native validation was supposed to handle for you.
The error messages themselves are another pain point. Native browser validation error messages are generic: “Please fill out this field” or “Please enter an email address.” These are technically accurate but not helpful. A better error message explains specifically what’s wrong and how to fix it: “Password must be at least 8 characters and include a number.”
Customizing these messages requires the Constraint Validation API’s setCustomValidity() method, but that only changes the message in the browser’s tooltip. You still need additional markup and JavaScript to display those messages in an accessible way for screen reader users.
For screen reader users to receive error information reliably, you need several components working together: aria-invalid="true" on the invalid field, visible error text with a unique ID, aria-describedby linking the field to its error message, and ideally a live region announcing errors when they occur.
None of this comes automatically with native HTML validation. You’re layering ARIA attributes, managing DOM updates, and coordinating everything via JavaScript. Which is fine—it’s the right way to build accessible forms—but it means the promise of “just add validation attributes and you’re done” isn’t accurate.
The pattern attribute is particularly problematic for accessibility. You can validate against a regex pattern, which gives you precise format control. But the default error message is just “Please match the requested format,” which tells users nothing about what format is actually required.
You must provide a title attribute describing the pattern requirements, and even then, users need to know to look for the title attribute (shown as a tooltip on hover) to understand what’s required. Better to have explicit help text visible next to the field explaining format requirements upfront, so users don’t have to fail validation to discover the rules.
Required field indication is another area where the defaults fall short. The required attribute makes the field required, but doesn’t communicate that visually except through browser-native styling that varies widely. You need to add explicit visual indicators—usually an asterisk or “required” text—and associate it with the field using aria-required or including it in the label.
The focus management when validation fails needs attention too. If a user submits a form with errors, what should happen? Ideally, focus moves to the first invalid field, making it obvious where attention is needed. Native validation doesn’t do this automatically—the form just doesn’t submit and tooltips appear. Users without clear visual focus might not notice anything happened.
JavaScript form validation libraries exist to solve these problems, providing accessible validation patterns that work consistently across browsers. But this brings us back to the beginning: if you’re including a validation library anyway, you’re not really using native HTML validation—you’re using a JavaScript solution with better accessibility.
There’s also the question of server-side validation, which you need regardless of client-side approach. Client-side validation improves user experience by catching errors before submission, but can always be bypassed. Your server must revalidate and handle errors gracefully, which means you need error handling logic in multiple places.
What I’d like to see is browser implementations improving the accessibility of native validation so that it works reliably with assistive technology out of the box. Automatically setting appropriate ARIA attributes, providing better hooks for custom error messaging, handling focus management sensibly. Some of this is possible within the current standards—it just requires better implementation.
For developers today, the practical approach is understanding that HTML validation attributes are useful for basic validation logic, but accessible error messaging requires additional implementation. Don’t assume that adding required or type="email" makes your form accessible—test with actual assistive technology and fill the gaps.
The checklist for accessible form validation includes: visible error messages associated with fields via aria-describedby, aria-invalid toggled appropriately, clear indication of required fields, helpful error message text explaining what’s wrong and how to fix it, and sensible focus management when validation fails.
None of this is particularly complicated, but it’s also not automatic. Forms are a fundamental web interaction pattern, and getting them right for all users requires more than the minimum implementation. HTML validation attributes are a good starting point, not a complete solution.