Summary

Popular screen readers use a virtual buffer to allow users to interact with web content. This article uncovers undocumented behaviour in JAWS 7.1 and later, which allows web developers to build Ajax applications that update the virtual buffer without any interaction from the user.

Author: Gez Lemon and Steve Faulkner

Contents

The Virtual Buffer

In a previous article, we demonstrated how Ajax applications could be made accessible to screen readers. In essence, this involves screen reader users understanding the concept of a virtual buffer, and knowing how to update the virtual buffer. Understanding the virtual buffer is essential for empowering screen reader users, particularly considering the number of Web 2.0 applications that depend on Ajax. Screen readers typically take a snapshot of a web page, and place the content in a virtual buffer to allow the user to interact with the content.

Screen readers that use a virtual buffer offer commands to manipulate the buffer, such as P to navigate to the next paragraph. When a screen reader user attempts to enter data in a form, the virtual buffer cannot be active, or their keystrokes will be used to interact with the buffer, rather than interact directly with the form controls.

As an example, if a screen reader user were to enter the word Harry in a text edit box, then when they typed H for the first letter, most screen readers would announce the next heading (or previous heading if the user pressed Shift + H), as that is the purpose of the virtual buffer; it provides a convenient mechanism for screen reader users to interact with HTML content.

Toggling the virtual buffer off and on will also update the virtual buffer, although there is usually a specific command to update the virtual buffer. For example, the virtual buffer can be updated in JAWS at any time using Insert + Esc. This is the most empowering command for screen reader users — if a screen reader user interacts with an application that doesn't appear to be responsive, the best course of action is to update the virtual buffer and re-investigate the content.

Improvements in JAWS

In JAWS 7.1 and later, Freedom Scientific introduced behaviour that makes it a little easier for developers to consider screen reader users when developing Ajax applications. In previous version of JAWS, the virtual buffer was always updated one step behind when the spacebar is pressed to activate a form control; that is, the virtual buffer contained the content displayed on the screen before the current update (this article only considers Internet Explorer 6 and 7, as although Firefox has limited support with JAWS, that support is way behind Internet Explorer, as this is what Freedom Scientific have chosen to support). In other words, there was a disconnect between what was displayed on the screen, and what JAWS reported to its users.

In JAWS 7.1 and later, dynamic updates that result from the user activating a link with the keyboard will automatically update the virtual buffer so that it is synchronized with the content on the screen. This is a significant improvement in JAWS, and means that users don't have to be so concerned about updating the virtual buffer themselves. However, a lot of Ajax-type applications typically update content in response to a variety of form controls, and JAWS does not automatically update the buffer in response to these controls. The virtual buffer is also not updated when a mouse is used to interact with an interface element. This is probably because Freedom Scientific consider that the majority of their users are blind (and unable to use a pointing device), although it is common for people with learning/cognitive difficulties to also use screen readers.

The Update Virtual Buffer Function

In JAWS 7.1 and later, certain script statements cause the virtual buffer to be updated without any interaction by the user. For example, under certain conditions, content updated using innerHTML will cause the virtual buffer to update; after the update, the virtual buffer won't contain the content added with innerHTML, but will contain the content before the function was called, so this could be used at the end of an Ajax call to update the virtual buffer. On the surface, this appears to be great news, but innerHTML is not DOM compliant. On further investigation, we discovered that the virtual buffer is also updated when the setAttribute method is called to update a form control's value. With this in mind, we realised that we could automatically update the virtual buffer in JAWS 7.1 and later with two simple functions; one to add a hidden form element to the document, and another to update the hidden element in response to an Ajax call. The function prepareBuffer adds a hidden input element to the end of the document with the name, virtualbufferupdate. This function should be added as soon as possible (ideally, when the page loads).

function prepareBuffer()
{
    var objNew = document.createElement('p');
    var objHidden = document.createElement('input');

    objHidden.setAttribute('type', 'hidden');
    objHidden.setAttribute('value', '1');
    objHidden.setAttribute('id', 'virtualbufferupdate');
    objHidden.setAttribute('name', 'virtualbufferupdate');

    objNew.appendChild(objHidden);
    document.body.appendChild(objNew);
}

The function updateBuffer updates the value of the hidden form control, which in turn updates the virtual buffer. This function should be called towards the end of the callback function that is assigned to the onreadystatechange event handler for the Ajax call.

function updateBuffer()
{
    var objHidden = document.getElementById('virtualbufferupdate');

    if (objHidden)
    {
        if (objHidden.getAttribute('value') == '1')
            objHidden.setAttribute('value', '0');
        else
            objHidden.setAttribute('value', '1');
    }
}

The pseudo code for our complete application may look as follows:

function init()
{
    // Statements required by the init function

    someElement.onclick = function(){return updateContent(this);};
    prepareBuffer();
}

function updateContent()
{
    // Setup XML HTTP request object
    // ...
    if (objXMLRequest)
    {
        objXMLRequest.onreadystatechange = processResult;
        objXMLRequest.open('GET', 'somefunc.php', true);
        objXMLRequest.send(null);
    }

    return true;
}

function processResult()
{
    // When we're sure the status of the XML HTTP request
    // object is suitable, do our thing ...

    updateBuffer();

    // focus on an object if need be
}

Conclusion

JAWS 7.1 makes significant improvements over previous versions, in that the virtual buffer is automatically updated in response to a link being activated by the keyboard. The updateBuffer function presented here extends the limited improvements in JAWS 7.1 and later, by providing a mechanism to update the virtual buffer for other interface elements, that works regardless of input device. This means that users of JAWS 7.1 and later do not need to explicitly update the virtual buffer in order to interact with Ajax applications. Of course, this depends on the developer providing an updateBuffer function, or equivalent, so it is ultimately always far better that screen reader users understand how the virtual buffer works. This hack does, however, at least provide a method for developers to provide confidence to screen reader users with JAWS 7.1 and later in a way that does not have a detrimental affect for other users.

Translations

Category: Accessibility.

Comments

  1. [improving-ajax-applications-for-jaws-users.php#comment2]

    This is great information, as always. Thank you for being so committed to accessibility issues.

    Since many (most?) screen reader users will have a pre-7.1 version of JAWS for months, if not years, to come, don't forget, developers, to write your code so that it degrades gracefully. Bells and whistles aside, this will help ensure that your apps are accessible for most everyone.

    Thanks!

    Posted by Mike Elledge on

  2. [improving-ajax-applications-for-jaws-users.php#comment3]

    I too will throw in my congrats on extremely useful information here guys. Well done... I am now about to do an email blast to the entire campus.

    Keep up the good work!

    Posted by John Foliot on

  3. [improving-ajax-applications-for-jaws-users.php#comment4]

    I really don't know what "degrade gracefully" means in terms of Ajax. In fact, I think it may have no meaning at all. If we could do things without JavaScript, we would. If you have JS turned off (not that anyone does) or you have something functionally equivalent in a screen reader that can't follow updated sections of a page, well, you're just going to miss out.

    There is no way to progressively enhance every Ajax application so that JS and no-JS are equivalent. That's outdated WCAG thinking that has been overtaken by events. Perhaps we should stop reiterating "degrade gracefully" as though it were some kind of koan.

    The solution is to make JavaScript and Ajax applications and adaptive technology accessible and mutually compatible. The techniques here are a hack until that happens.

    Posted by Joe Clark on

  4. [improving-ajax-applications-for-jaws-users.php#comment5]

    Joe Clark:

    The techniques here are a hack until that happens.

    Indeed it is "a hack", which we acknowledge:

    This hack does, however, at least provide a method for developers to provide confidence to screen reader users with JAWS 7.1 and later in a way that does not have a detrimental affect for other users.

    Posted by Steve Faulkner on

  5. [improving-ajax-applications-for-jaws-users.php#comment6]

    Really good work Gez and Steve.

    I somewhat agree with Joe but not entirely. Until we have some way to define what should be highlighted to the user on change and what shouldn't screen readers which automatically follwed updating content, or announced updates as they happen could be really detrimental.

    The web is becoming applications the screen reader can't anticipate the needs of the application and if they try I foresee rather a lot of false positives.

    This technique is good in that it's still up the web application developer to focus on the right place after updates, or not at all.

    I wrote some more thoughts about this post, that are not related to Joe's comments on my blog.

    http://www.kid666.com/blog/2007/01/19/escape-from-the-jaws-of-inaccessibility/

    Posted by Tom on

  6. [improving-ajax-applications-for-jaws-users.php#comment7]

    Muchas gracias, Gez and Steve. Sterling work, once again.

    When it comes to Ajax and screenreaders, all we have to work with are hacks: we're hacking around the limitations of the technologies. As hacks go, this is pretty damn clean.

    Posted by Jeremy Keith on

  7. [improving-ajax-applications-for-jaws-users.php#comment8]

    Good work guys.

    It looks like a practical workaround that can facilitate behind the scenes buffer updates for legacy UA's without burdening the user with info about the buffer at all.

    Though if screen reader users knew more about the buffer that would be no bad thing *smile*

    Jeremy Keith said:

    When it comes to Ajax and screenreaders, all we have to work with are hacks: we're hacking around the limitations of the technologies.

    Thats exactly right, as there is a disconnect between where we are at and the technologies promise.

    Posted by Joshue O Connor on

  8. [improving-ajax-applications-for-jaws-users.php#comment9]

    Gez and Steve,

    Very interesting! The question is open as to whether it's a good idea to actually use the technique. I've used lots of hacks in my time and don't know if I want to use more.

    In any case, I'm also curious about affects, adverse or otherwise, on other technologies. What if GW Micro adopts the technique for Window Eyes next week?

    To that end, I've built a couple of test cases over at Access-Matters. Amble on over and try then out:
    http://www.access-matters.com/2007/01/22/improving-accessibility-for-todays-ajax-to-hack-or-not/

    Posted by Bob Easton on

  9. [improving-ajax-applications-for-jaws-users.php#comment10]

    I've used lots of hacks in my time and don't know if I want to use more.

    That's fair enough; we're not trying to force techniques on people. We're merely suggesting techniques that can be used by people who want to make Ajax more accessible.

    In any case, I'm also curious about affects, adverse or otherwise, on other technologies. What if GW Micro adopts the technique for Window Eyes next week?

    If Window-Eyes update their virtual buffer in response to this technique (they don't at the moment), that would be a good thing, as there wouldn't be a disconnect between what is displayed on the screen, and what is reported to the screen reader user. Why do you see that as a bad thing? More importantly, if JAWS, Window-Eyes, and every other assistive technology eventually work well with rich internet applications, developers that employ this technique can simply remove it.

    Posted by Gez on

  10. [improving-ajax-applications-for-jaws-users.php#comment11]

    To that end, I've built a couple of test cases over at Access-Matters. Amble on over and try then out:

    Bob, the 2 test cases you have created are going to provide the same result for JAWS 7.1+.

    To clarify: In JAWS 7.1+ the updatebuffer function is not needed on a link that triggers an AJAX style update, if it is activated via the keyboard. The virtual buffer update is provided by JAWS. What our hack does is to extend the (half-assed) functionality implemented in JAWS by Freedom Scientific, to the button element and input type [button, image, checkbox, radio button]. It also extends the functionality to all of the above including links when they are activated via a mouse click.

    I would be very surprised if this technique had any adverse effect upon other AT as all that it is doing is changing an input type=hidden value attribute's value. I have checked it with the latest version of Window Eyes (6.0) and found that unfortunately it stubbornly refuses to update the virtual buffer.

    Posted by Steve Faulkner on

  11. [improving-ajax-applications-for-jaws-users.php#comment12]

    Gez said:

    If Window-Eyes update their virtual buffer in response to this technique (they don't at the moment), that would be a good thing, as there wouldn't be a disconnect between what is displayed on the screen, and what is reported to the screen reader user. Why do you see that as a bad thing?

    Sorry, that wasn't my intent. I see it as a GOOD thing when any of the AT becomes more responsive. OTOH, that responsiveness really should be triggered at a lower level, ideally at the operating system level so the AT doesn't have to depend on endless layers of detection.

    Posted by Bob Easton on

  12. [improving-ajax-applications-for-jaws-users.php#comment13]

    Steve said:

    What our hack does is to extend the (half-assed) functionality implemented in JAWS by Freedom Scientific, to the button element and input type [button, image, checkbox, radio button]. It also extends the functionality to all of the above including links when they are activated via a mouse click.

    Thanks for that clarification. I jumped too quickly to the simplest case, a link. When I can get to it, I'll update the test cases to use a button.

    Nor was I expecting any adverse effects. Just seeking to document what helps. And no, I don't really expect earlier versions of JAWS to be helpful. Yet, here will be test cases for people to try for themselves.

    Thanks again!

    Posted by Bob Easton on

  13. [improving-ajax-applications-for-jaws-users.php#comment14]

    Thanks Steve for clarifying the purpose of the hack, and Bob for promising to update the test cases as this jaws user was for one a little confused by the similarity in result and expected behaviour in both cases. To continue the concern I raised over at Access-Matters, while removing the need for the user to manually update the buffer is certainly a very significant improvement the fact remains that causing an action on one part of the page to provoke a response elsewhere on the page is problematic for users of a screenreader which can by any nature only focus on any one point at a time. Might one usercentric use of this hack be to inform the user at the point of the activated link (button etc), (possibly via the form label / description) where on the page content has changed, or will change.

    Posted by Adrian Higginbotham on

  14. [improving-ajax-applications-for-jaws-users.php#comment15]

    I have been trying to live in the AJAX Web 2.0 world as well as in the accessible world. I have started using a dual approach where I use AJAX to add dynamic content to pages when not in the accessible mode; and I use an embedded iframe to display the dynamic content when rendering an accessible page. I carefully set focus to the iframe when the dynamic data finishes being loaded. My question is whether this iframe approach to showing dynamic data on the page is workable with the various readers.

    Thanks,

    Peter

    Posted by Peter Hurley on

  15. [improving-ajax-applications-for-jaws-users.php#comment16]

    To continue the concern I raised over at Access-Matters, while removing the need for the user to manually update the buffer is certainly a very significant improvement the fact remains that causing an action on one part of the page to provoke a response elsewhere on the page is problematic for users of a screenreader which can by any nature only focus on any one point at a time.

    This is a good point, and something I'm working on at the moment. This particular problem will be solved when WAI-ARIA is a stable recommendation and supported by user agents, but is a significant problem today. I'm currently working on a technique that bridges that gap, but uses WAI-ARIA recommendations when supported.

    Might one usercentric use of this hack be to inform the user at the point of the activated link (button etc), (possibly via the form label / description) where on the page content has changed, or will change.

    Yes, updating a screen reader's virtual buffer is only a small part of the problem; without an announcement, screen reader users might not realise that anything has happened. Even when they are aware something has happened, there is still the issue of allowing screen reader users to investigate the document without forcing them through the updates. The announcements also have to be carefully handled, or screen reader can end up overloaded with a queue of update announcements. I'm hoping to have some follow-up information on this soon.

    Posted by Gez on

  16. [improving-ajax-applications-for-jaws-users.php#comment17]

    Hi Gez, great article

    Joe said:

    I really don't know what "degrade gracefully" means in terms of Ajax. In fact, I think it may have no meaning at all. If we could do things without JavaScript, we would. If you have JS turned off (not that anyone does) or you have something functionally equivalent in a screen reader that can't follow updated sections of a page, well, you're just going to miss out.

    About JS not being switch on, there was a valid point from media 2006 which Jeremy Keith talked about. This was about "not creating important content using the DOM". So I guess using JS would not be a problem if you site can still deliver the content intended if JS is switch off?

    Posted by Gaz on

  17. [improving-ajax-applications-for-jaws-users.php#comment18]

    The issue of screen readers and how they handle updates to page content came up during Bruce Lawsons talk at WebDD and then again in Dave Verwers presentation later on, obviously something which there's a lot of confusion over so info like this is always welcome.

    Cheers Gez, good to see you're on the case *smile*

    Posted by John Baxendale on

  18. [improving-ajax-applications-for-jaws-users.php#comment19]

    It would really be extremely useful to have a test case for this
    problem. As it currently is, I do not understand the exact nature of
    the problem. At least with jfw 8, the virtual buffer seems to get
    updated fine as a result of form actions. For example:

    http://openprinting.org/printer_list.cgi

    Consider the first two comboboxes on the page. If a printer
    manufacturer is chosen from the first combobox, the second one is
    updated to list the printers from the selected manufacturer. This
    update is clearly done via javascript, more specifically via the
    onchange event handler on the first combobox. I guess this is thus not the
    kind of situation the article is aiming at, but what is it then?

    Posted by Lukas on

  19. [improving-ajax-applications-for-jaws-users.php#comment20]

    ATs like screenreaders are falling through the net of progressive enhancement - it's not enough to provide a JS application that degrades gracefully to non-JS, because the reader *is* a JS device, but it needs the non-JS version.

    So until such time as: ATs can deal with Ajax apps just like graphical browsers; or, we know that all AT users have JS switched off; Ajax is and remains an immature technology that is not yet ready for primetime use.

    Ajax is not cool, but it will be cool! But before we can begin to developer proper, accessible Ajax, the first thing we must do is back down.

    This is a great article and a step closer to the holy grail. Sure it's hack, but *all* web applications are hacks - HTTP was not designed to have state *wink*

    Posted by brothercake on

  20. [improving-ajax-applications-for-jaws-users.php#comment21]

    Lukas said:

    It would really be extremely useful to have a test case for this problem. As it currently is, I do not understand the exact nature of the problem. At least with jfw 8, the virtual buffer seems to get updated fine as a result of form actions.

    There are many situations where JAWS 7.1 and later updates the virtual buffer correctly, but there are also cases where the virtual buffer is not updated. For example, the latency from an Ajax call might result in the virtual buffer being updated before the onreadystatechange event has completed. Another example is with custom controls, such as a tree view, where JAWS doesn't realise that the virtual buffer should be updated in response to user actions; this particular example also has other issues, but this article is just interested in the virtual buffer representing what is actually on the screen. Updating content in a hidden form element forces JAWS to update the virtual buffer, so if it's called after the DOM has changed, the virtual buffer matches what is actually on the screen.

    Posted by Gez on

  21. [improving-ajax-applications-for-jaws-users.php#comment22]

    Brothercake said:

    So until such time as: ATs can deal with Ajax apps just like graphical browsers; or, we know that all AT users have JS switched off; Ajax is and remains an immature technology that is not yet ready for primetime use.

    I completely agree that Ajax is an immature technology; or at least, as a technology, it lacks a convenient mechanism of notifying assistive technology that the view has changed, what parts of the view have changed, and providing a non-invasive method of allowing users to easily investigate those changes. WAI-ARIA's AJAX Live Regions will bridge that gap, but that route also depends on user-agent support. Considering that some assistive technologies, such as screen readers, are incredibly expensive, it's not reasonable to assume that the problem will be solved at the point WAI-ARIA becomes a recommendation with support from the latest versions of screen readers.

    Unfortunately, the lack of a decent accessibility architecture and user-agent support won't stop or slow down the production of Ajax-based applications due to their perceived coolness. Like you, I would prefer people didn't produce these types of applications until the support is properly in place. At the same time, if developers are going to continue to produce Ajax-based applications, I would hate to see other areas of accessibility being overlooked. If we can't persuade people to wait until the technologies are in place, I think the best we can do at this point in time is to highlight the problems these kinds of applications cause, suggest workarounds where possible, and emphasise that other areas of accessibility (people with mobility disabilities, cognitive disabilities, sensory disabilities, such as poor vision, hearing impairments, etc.), are equally as important as people who are blind and depend on screen readers.

    This is a great article and a step closer to the holy grail.

    Cool - thank you.

    Posted by Gez on

Comments are closed for this entry.