Your code is correct. Apparently, the "1 behind" has been discovered. From the link, it looks as if using aria-atomic="true"
may fix the problem. However, the example as given does work properly in IE9 and Firefox.
If you haven't stumbled across them already, check out the test-cases on codetalks and accessibleculture.org. There are a lot of subtle differences to be aware of. Just don't be surprised when the tests fail! Over the past year or so, I've come across a few (inadequate) tricks which may help you.
Method 1: role="alert"
The alert
role is supposed to be equivalent to aria-live="assertive"
, but older versions of JAWS didn't handle it properly. Check out these examples from February 2011, which states that:
If you are looking to support JAWS 10 in IE7 or IE8 at all, it is likely best to double up on alerts with both role="alert" and aria-live="assertive". While this is somewhat redundant since, by definition, the alert role is to be processed as an assertive live region, doing so does allow JAWS 10 to automatically announce the updated alert's contents in those two browsers.
Both Firefox4+ and IE9 do not require this. But it would be something like this:
<div id="statusbar" role="alert" aria-live="assertive">
Contents will be spoken when changed
</div>
Method 2: focus forcing hack
By dynamically creating a DOM element and forcing focus to it, you can "trick" most screen readers into reading the contents. It's hackish, but effective...and somewhat the point of the Create and Focus example. Simplified, you can do something like this:
<div id="statusbar" role="alert"></div>
$('#statusbar')
.clear()
.append('<div tabindex="-1">' + newString + '</div>')
.children().first().focus()
;
Merely hiding/showing the contents instead actually works fairly well most of the time. However, VoiceOver's focus lingers on the element and does not speak its contents when shown again. Thus, removing it from the DOM seems to be the most foolproof method for now. I don't like it, but such is the state of things.