JavaScript and accessibility

A note about the external links:
All external links on this page, with the exception of those leading to W3C and Evolt, are taken from the first three pages I got when googling for 'JavaScript accessibility' in March 2003. I consider them a fair sample of currently available web pages on this subject.
I am notoriously sloppy in updating links, so if you notice a dead link, please mail me.

On this page I give a short introduction to the accessibility issues surrounding the use of JavaScript. It is by no means a complete tutorial; I just want to offer a few rough guidelines and some bits of information.
Nonetheless the information on this page seems to be clearer and more complete than the average "JavaScript and accessibility" page on the WWW.

Regarding JavaScript and accessibility, there are two myths:

  1. Using any JavaScript at all means that your site is inaccessible.
  2. It's impossible to build a modern site without JavaScript, so it's just Too Bad For Accessibility.

Neither of these myths are true. As happens so often, the truth lies in the middle.

To come closer to the truth, take the last website you produced and look at it again. Then turn JavaScript off (see the Browsers pages for instructions how to do this). Reload the site and see if it still works. If you cannot access navigation or content, carefully note which JavaScript functionality causes the problem. Don't worry about solutions yet, first read this page.

Or read this story about websites that are inaccessible without JavaScript. It gives a practical example of the problems JavaScript pages can cause in a noscript browser.

This page inevitably starts with the W3C's guidelines, followed by a discussion of the noscript tag, which turns out not to be as useful as it seems.
Then we'll encounter the lack of general rules that requires us to perform a lot of case studies to study accessibility issues for important scripts on this site. Case studies are the only correct way to solve these issues.
Events are a separate problem. This issue is quite confused by badly thought out and sometimes contradictory guidelines on several sites. Finally it's time for a conclusion and some useful links.

W3C WAI

Of course we start with the W3C WAI Guidelines:

"Ensure that pages are usable when scripts, applets, or other programmatic objects are turned off or not supported.
If this is not possible, provide equivalent information on an alternative accessible page."

I intensely dislike the second alternative. As soon as you create two versions of the same page you also create serious problems for the people who're going to update the site. Besides, it's simply not done.

As to the first alternative, it is perfectly logical and possible, as long as we use a practical definition of "usable". In my view, a usable site is any site that allows any visitor to read and use its content and navigation. Nothing less, but also nothing more.

W3C gives an example of dealing with scripts and accessibility, which unfortunately is somewhat marred. First of all it uses the obscure TCL scripting language that is completely irrelevant to the WWW, secondly the code is not an example of well thought-out accessibility.

In the example, the information generated by the TCL script is repeated in plain HTML. The HTML is placed within a <noscript> to hide it from script-capable browsers. In itself this is an excellent idea, but one does wonder why we need a script when the information can (apparently) also be generated through a server side script. I'd remove the script entirely and rely on server side generation exclusively.

This curious example has been uncritically copied by some sites, even though it fails to give a practical solution to any problem.

Noscript

W3C's example does point to one of the principal tools for ensuring accessibility: the <noscript> tag. Although all "JavaScript and accessibility" pages note the use of this tag, they are sometimes confused about its practical use.

Can the <noscript> tag solve accessibility problems? Of course it can. But it's not the end-all of accessible sites it's sometimes made out to be.

W3C itself is careful to note that using <noscript> is only one way of solving accessibility problems, though it doesn't give any details.
trace.wisc.edu maintains that a <noscript> alternative must be added to every single script, which is obviously nonsense (how do you provide a noscript alternative to form validation?).
Fortunately www.webaim.org does make a distinction between useful and useless <noscript> tags and even explains this distinction.

Basically, <noscript> can provide an alternative text for a script, but rarely more than that. So the first question is: do you need an alternative text? If you don't, you don't need <noscript> either.

Even if you do need alternative texts, and thus the <noscript> tag, you may encounter problems. For instance, take this hypothetical code for a DHTML navigation:

<script>
for (var i=0;i<x.length;i++)
{
document.write('<a href="page'+i+'.html" onmouseover="doDHTML()">Link '+i+'</a>');
}
</script>
<noscript>
<a href="page1.html">Link 1</a>
<a href="page2.html">Link 2</a>
[etc]
</noscript>

Sure, this will work. The problem, however, is that you have to update the navigation in two places, in the array x which the script uses and in the noscript alternative. I don't like that at all, it makes for complicated sites. Besides, some judicious HTML structuring may make <noscript> unnecessary, as we'll see below.

Concluding, <noscript> is a useful tool for solving some accessibility problems, but its use doesn't guarantee accessibility at all. And remember that it doesn't work in Netscape 2, so the few surviving Netscape 2 users will see both the script and the noscript versions of your page.

General rules?

Does using JavaScript make a site inaccessible? Not in and of itself. Using JavaScript for extra functionalities is quite allowed. It could even be argued that the <script> tag itself is an important tool for creating accessible JavaScript pages. When adding advanced effects to your pages, you could choose to generate the necessary HTML entirely by JavaScript. Thus you don't need noscript messages (which tend to be rather disappointing to your users, anyway). We'll see an example of this when we study accessible DHTML navigation.

So there's no easy good and bad.

Unfortunately most of the "Accessibility and JavaScript" pages I read are quite vague and incomplete. They prominently quote or paraphrase the W3C WAI Guidelines and speak in strong terms about the necessity of accessible pages, but mostly fail to give practical information.

A welcome exception is the NCI Web Accessibility site, which said, before it went offline:
'"Accessible" javascript techniques are still very much a work in progress; the lively debate on developer listservs and bulletin boards will give you valuable tips, but also underscore the substantial uncertainties that characterize this topic. Over time, best practices will emerge in the javascript community. For now, we've attempted to summarize the known issues, workarounds, and suggestions, but remember: everything must be tested!'

This is quite correct. There are no general rules. The only way to ensure accessibility and JavaScript living in harmony is by evaluating each individual script and devising a unique solution to the accessibility problems it poses.

Case studies

Since there are no general rules, we should proceed on a case-by-case basis. Therefore I review the accessibility problems (or lack thereof) of some important scripts on this site. I hope these examples will give you some ideas of your own.

First of all we have to define the purpose of the script. Is the script required, useful or merely ornamental? In general, useful or ornamental scripts can be switched off without trouble. Required scripts cause far more problems and need some judicious accessibility enhancements.

After defining the purpose of the script I review the effects in three user agents:

  1. Noscript browsers: traditional graphical browsers with JavaScript turned off (or completely absent)
  2. Speech browsers and mobile phones as representatives of non-standard user agents.
    For argument's sake these devices have JavaScript turned on. Non-traditional user agents with JavaScript support are very rare (IBM's HomePage Reader was the only one I could find, but it's just a skin on top of Explorer), but let's pretend they're common.

Finally I take a look at the solution of the problems (if any). In general we'll see that the more advanced a script is, the more accessibility problems it causes.

Mouseovers

No problems

Purpose of the script: Creating a nice graphical extra that makes the site more lively. Sometimes it conveys information ("You are here").
(Script)

Solution: None necessary, as long as you make sure the mouseovers don't convey critical information.
So it's simple. Complicated solutions like this one are quite unnecessary.

Detection scripts and page redirection

No problems

Purpose of the scripts: Show different content or to redirect users to a different page depending on the capabilities of their browsers.
(Examples: Browser detect, Flash detect, Customized framesets)

Solution: Always let all users enter your site at the simplest possible page. This page may contain a script that redirects the user. If the browser can handle the script it is redirected, if it can't it stays on the simple page. No problems either way.

<script>
location.replace('page_with_javascript.html');
</script>

<p>This is the simple page. If your browser can handle it, you may
<a href="page_with_javascript.html">go on</a> to the JavaScript
enhanced page.</p>

<p>[Start of the actual content]</p>

My own site doesn't quite work that way; noscript users get a plain vanilla link leading to the homepage. But since my site is about JavaScript, I (almost) require all users to have JavaScript enabled.

Form validation

No problems

Purpose of the script: Useful. It validates form entries in the most user friendly way possible. Any form should be validated on the server, too.
(Script)

Solution: None necessary, as long as you also validate the form server-side.

Required reading: Forms & JavaScript Living Together in Harmony by Jeff Howden.

Selects and options

Accessibility alert

Purpose of the script: Scripts that do something with select boxes are usually meant for navigation. Therefore we immediately flash the accessibility alert: since any browser should be able to access the site navigation, any navigation that uses select boxes and JavaScript should be repeated in plain links.
(Examples: Select box navigation, Dynamic options)

Solution: Repeat the navigation in plain links, possibly hiding them from modern browser through the <noscript> tag. If you don't repeat the navigation, your site is inaccessible.

Another solution would be to add a Go! button that sends the form to a little server side script to do the redirecting. Once again, you can hide this button in a <noscript> tag.

Popups

Be careful

Purpose of the script: What is the purpose of popups...? I generally dislike them, though I must admit that once in a very great while a popup may have a legitimate function (navigation, extra messages). Too often they're a crutch for people who don't want to spoil their beautiful design by inserting content.
(Script)

Solution: Make sure that noscript browsers follow a plain link to the page shown in the popup:

function popitup(url)
{
	newwindow=window.open(url,'name','height=200,width=150');
	if (window.focus) {newwindow.focus()}
	return false;
}

<a href="popupex.html" onClick="return popitup('popupex.html')"
	>Link to popup</a>

Call the popup script from an onclick event handler which returns false. This prevents the browser from following the actual href. Only when JavaScript is disabled does the browser follow the link and show the popup page in the main window.

Required reading: Links & JavaScript Living Together in Harmony by Jeff Howden.

DHTML navigation

Be very careful

Purpose of the script: To provide access to all pages and to give a clear sitemap-like overview of the structure of the site.
(Script)

Solution: The placement of the DHTML layers in your source code is of prime importance. They're traditionally placed at the top, but without JavaScript the page would start with 30 or 40 links in no apparent order, causing terrible confusion.

In general I think it's best to show the 'root' navigation at the top of the page, where noscript browsers can easily access it. The other layers, however, should be placed at the bottom of the page, so that the content starts immediately after the 'root' block and users of noscript browser immediately see it.

The only layer that may also be placed at the top is the one that shows the subnavigation of the part of the site the page is in.

Accessify suggests you should generate all navigation layers except for the 'root' block by JavaScript, because this creates better accessibility! The idea is very interesting, since users of noscript browsers would be spared seeing lots of links without context. Nonetheless this solution could lead to problems, too, since you'd have to define a second way of navigating the site without JavaScript.

W3C DOM scripts

Serious, insolvable problems

Purpose of the scripts: To allow the user to change (parts of) the page for better usability or for doing something with the content.
(Examples: Edit text, Extending forms)

Solution: None, really. W3C DOM applications won't become accessible in the near future.

Events

A separate problem is the correct use of events. Speech browsers and mobile phones don't have a mouse, so making mouse events accessible can be quite problematical.

The general rule is that when you use events to trigger scripts, you should choose those events that are supported by as many devices as possible.

In fact, this rule has little to do with accessibility. When writing event-triggered scripts for traditional JavaScript browsers, you should also choose those events that ensure maximum cross-browser compatibility.
Therefore we need a good compatibility table that tells us which events are supported by which speech browsers, mobile phones or other devices. I haven't found one as yet, and I don't have the money to buy all the devices I should test to create this table.

Many "JavaScript and accessibility" web pages go into a flurry of activity by making rules for the events hypothetical non-traditional browsers with JavaScript enabled might (or might not) support. Although most of these rules are worth a second look, some of them are just assumptions without any practical basis.

W3C

W3C gives the following three rules:

  1. It's best to use interface events like blur, focus and select. Device-dependent events like mouseover or keypress may not be supported by a speech browser, which uses neither mouse nor keyboard. Interface events, though, are device-independent. A focus event on a link takes place whenever the user goes to a link, whether by a mouse click or by the Tab button.
  2. When this is not possible, use complementary events that allows for different devices. Always use keydown with mousedown, keyup/mouseup, keypress/click. Thus the script will be called when the user uses the mouse and also when he uses the keyboard.
    Don't use dblclick.
  3. Don't write scripts that depend on mouse coordinates. If the user doesn't use a mouse they won't work.

I agree with rules 2 and 3. Rule 2 allows users of traditional browsers to use the keyboard instead of the mouse.

Rule 3 at first sight seems to be rather restrictive, but it can be worked around easily. Usually, the purpose of a script that depends on mouse coordinates is to show something, a layer for instance, on or right next to the element the user has moused over or clicked on. When the user uses a keyboard or other navigational devices, the script won't find any mouse coordinates and would behave erratically.

Solution: don't detect the mouse coordinates. Instead, find the position of the element the user has moused over or clicked on and use these coordinates to place your layer.

As to rule 1, I'm less sure. A focus event simply isn't the same as a mouseover event. Besides, rule 1 heavily depends on the way non-traditional devices define the various events. W3C conservatively assumes they won't define mouse events, but why shouldn't they?

They might equate a focus event on a link with a mousedown event, since both events are a necessary preparation for a click event on the link.
Similarly, a user hitting 'Return' when the focus is on a link also causes a sort of click event, even though he doesn't use the mouse.

So it's all a matter of definition. Traditionally browser makers try to incorporate all code that is in common use, and certainly mouseover is the most common event. So I confidently expect non-traditional user agents to define mouse events, too. This makes rule 1 less important than the other two.

Others

The WebAim site adds some interesting notes.

It advises against using the change event, contrary to what W3C advises.
"When a user tries to scroll the list of options, the JavaScript interprets this scrolling as an "onSelect" event, which then sends the user to another page. It is nearly impossible to navigate through such menu systems without a mouse."
Good thinking.

access-board.gov, the official site of the US Access Board, also has some notes on events. Curious is its insistence that the mousedown and mouseup events cause confusion. I disagree strongly: the average user doesn't notice the difference. Since mousedown/up events generally offer more information about the event than click, they are by far my preferred events.

As to the change event handler, access-board states that "it presents tremendous accessibility problems for many commonly used screen readers and should be avoided."
Unfortunately these tremendous problems are not further explained. In my opinion the tremendous problem is actually selecting an option from a pulldown, and not the event.

Finally, both park.org and trace.wisc.edu recommend "active triggering": you should use events where the user actually does something (like click or select) not events that occur without the user taking a conscious decision to do something (like mouseover or load).

Although this is not entirely untrue, I've got serious doubts about the inclusion of the load event. It can be argued that this event is an active trigger: the user has made the conscious decision to go to another page.

Conclusion

JavaScript and accessibility is very much an unexplored area, despite the confidence with which some sites advertise this or that solution which will cause all your problems to disappear.

As a JavaScript developer, you should start bearing accessibility issues in mind. This doesn't mean that you must immediately solve every single issue you find. Some are tough nuts to crack or even unsolvable. Nonetheless you should make an effort, or at least think about the issue, even though your conclusion might be that the script cannot be made accessible.

When you do find a nice solution to a nasty problem, please post it to mailing lists or forums you're a member of. Remember that there are many more developers working on the same problems and that they'll welcome a good idea.

(Please don't send your solutions directly to me. Usually I'm too busy to evaluate them and paste them into this page)

Links

Some useful pages: