This article investigates a method of providing client-side form validation through the DOM, and ensures that it works as expected with screen readers. Modern screen readers work relatively well with scripting, but it's the extra steps required to inform screen reader users that the content has changed that needs addressing.
Author: Gez Lemon
Generic Form Validation
Before I start, I would like to extend my gratitude to Jim Thatcher, who was kind enough and patient enough to provide invaluable feedback about how different screen readers worked with the scripts I tried. Without Jim's help, I would never have been able to come up with this technique.
I've been investigating techniques to provide client-side form validation through the DOM. Ideally, this should be a generic technique that could be applied to any page with any number of forms. The simplest way of handling this is to use the
class attribute, and assign a value indicating the type of validation required; for example,
class attribute can accept multiple class names with a space-separated string, it wouldn't impact on any other classes used. To include an input form control in the validation process just requires adding a class indicating the type of validation:
<input type="text" ... class="string">
Optional form fields that require no validation wouldn't require a validation class, but it's not unusual to have optional form fields that would require validating if something is entered. As the
class attribute can accept multiple class names, this can be achieved by just adding another class to the form control:
<input type="text" ... class="email optional">
In this case, the validation for email would only result in a submission error if the user has added an ill-formed email address. There is obviously no guarantee that just because the email address is a valid format that it actually exists, but we're only interested in making it easy for the user to correct mistakes without having to jump through hoops.
If the script is included on a page that has
form elements, each form is assigned a submit event handler. When the submit event is raised, the handler iterates through all form controls looking for the validation classes. If the validation fails, a nice error message is produced at the top of the form, with a list of links to the form controls that were not correct.
Client-Side Scripting and Screen Readers
All is well and good, except when a screen reader user tries the form. For example, after changing the DOM, Window-Eyes announces:
Loading Page, Load Done, Looking for visible line.
The last visible line is where they left off; the submit button. Screen reader users have no idea that extra content has been added to the page, without re-reading the whole page following the cue that the page has been reloaded. It's unreasonable to expect screen reader users to read the whole page again, and couldn't be considered an equivalent experience to a sighted user who can immediately see what has changed. Fortunately, the solution is very straightforward.
The solution is to simply set the focus to the start of the error message. To set the focus, we require an element that is able to receive focus, like an anchor element. We already have links indicating the error messages, so we could just set the focus to the first link in the list. This still wouldn't be considered an equivalent experience, as the screen reader user wouldn't be informed there is a submission error, but asked to enter something again. A better solution is to make the heading text "Errors in Submission" a link that points to the first error in the list. That way, screen reader users are explicitly told that there is an error with the form submission, with the ability to navigate through the error links. The error links themselves point to the input field in error. The downside to the solution is that the headings for the submission errors are now ugly links, but that is easily solved with a bit of CSS.
Because the heading is now a link to the first error, and the error link points to the form control with the error, Jim pointed out that a user might not realise there were other errors if they just followed the links. Jim suggested adding an error count to the title, so that the user is aware how many errors there are in the submission.
This solution works with Window-Eyes and JAWS, but doesn't work with HPR. I'm not entirely sure why the solution doesn't work with HPR, but it's likely to be to do with the way that HPR doesn't fire the
focus event for links.
To help clarify how it works, I've set up a demonstration page that uses the technique, along with the ECMAScript to produce the error message through the DOM. The demonstration page has two forms. The second form has two optional fields; one with no validation at all, and another that is validated if an email address is entered.
Due to the usual suspects not behaving correctly, the solution here uses the traditional event registration model rather than the correct DOM Level 2 Events Specification registration model. A far better cross-browser event registration technique can be seen from Scott Andrew LePera; I've stuck with the traditional model so as not to distract from the technique itself.