ARIA role=alert
is supported across modern browsers and assistive technology, but implementation in browsers differ, which can lead to role=alert
appearing to be unsupported.
role=alert
what does it do?
When an element has a role=alert
is displayed it triggers an alert event in the browsers implemented accessibility APIs. This is picked up by assistive technology (AT) and the text content of the element is announced, usually suffixed or prefixed by the word “alert”. It does not move focus in the browser or assistive technology to the element, it just causes the text content of the element to be announced. This is useful because on screen messages can be conveyed to AT users without breaking the flow of their page navigation or current focus. They get a similar experience to other users when a text message is displayed.
The WAI-ARIA Authoring Guide states:
Use the
alert
role for a one-time notification which shows for a period of time and goes away and is intended to alert the user that something has happened.
Note: role=alert
is one of the numerous ARIA features that are not available as native HTML features.
Different methods
There are numerous methods for displaying content on the page after the page has loaded. Trouble is in some browsers the differing methods do not all have the desired effect of triggering the alert event in the browser when role=alert
is present on the displayed content.
Method 1 createElement(), insertAttribute(), createTextNode() and appendchild()
Using this method a text alert can be displayed on the page by:
- creating a new element
- adding a role attribute with a value of alert
- creating the text content
- appending the text content to the created element
Note: this method only currently works with FireFox and Chrome
Method 2 innerHTML
Using this method an element with a role attribute with a value of alert and text content can be added to the page:
elementX.innerHTML = “<div role=’alert’>alert text</div>”;
Note: this method only currently works with FireFox and Chrome
Method 3 display:none to display:block|inline etc.
Using this method an element already in the DOM with a role attribute with a value of alert and text content can be displayed on the page.
Note: this method only currently works with IE, FireFox and Chrome
Method 4: createTextNode + constraints
Note: unfortunately method 4 is a big hack, but it is the only method that provides support across browsers/AT and platforms.
Using this method, an existing element with no text content can have text content added. There are additional constraints on this method to make it work with IE, Chrome and Safari (Mac/iPhone/iPad). Working example: Test Page – method 4
basic:
alertText = document.createTextNode("alert text"); elementX.appendChild(alertText);
Constraints:
- The element cannot be hidden (For safari) prior to adding the text so used CSS clip() and change before additon of text.
- The elements CSS visibility property must be toggled (for IE)
- Need an additional
role=alert
on outer container element and then only set therole=alert
on the inner element via scripting prior to adding text.
To achieve this outer element has its CSS clip
property initially set to rect(0px,0px,0px,0px)
, the inner element has role=alert
added and the outer element CSS clip property is set to auto via scripting (for Chrome), then after (for Safari) the text node is added, the CSS visibility
property is toggled (for IE).
HTML:
<div id="display2" role="alert"> <span id="add1"></span> </div>
JavaScript:
function addError(){ //set role attribute on inner element elem1.setAttribute("role", "alert"); ? //change initial clip property to auto document.getElementById('display2').style.clip='auto'; // create and append the text node alertText = document.createTextNode("alert via createTextnode()"); elem1.appendChild(alertText); //toggle visibility from visible to hidden and back again elem1.style.visibility='hidden'; elem1.style.visibility='visible'; }
CSS:
/* clip set to hide element initially as it cannot be hidden by display:none or visibility:hidden for Safari compatibility */ #elem1 { clip:rect(0px,0px,0px,0px); }
Note: this method as described works with FireFox, Chrome, IE on Windows and Safari (Mac, iPhone and iPad?).
Which browsers support which methods?
If the display of the alert text triggered an MSAA SYS_ALERT
event (on Windows) the method is considered as supporting role=alert
, after ad hoc testing with NVDA and JAWS. On Mac, iPhone and iPad? if VoiceOver announces the alert text the method is considered as supporting role=alert
.
Note: Results marked with an asterisk indicate that while a particular method is supported, support is brittle as , for example, an alert is not triggered if the method is reinstantiated on the same page after the initial use. In other words the only browser with robust support is Firefox.
browser | method 1 | method 2 | method 3 | method 4 |
---|---|---|---|---|
FireFox 13 | Yes | Yes | Yes | Yes |
IE 9 | No | No | Yes * |
Yes * |
Chrome 19 | Yes * |
Yes * |
Yes * |
Yes * |
Safari 5 (Mac/iPad/iPhone) | No | No | No | Yes * |
Differing browser implementations are a pain in the A
As can be seen from the above information, due to the IE and Safari support issues getting role=alert
to work cross browser & cross AT is extremely painful, but as shown it is possible. Perhaps I am missing something and a lot simpler solution is out there, If so please share!
Testing methodology
On Mac, iPhone and iPad, VoiceOver was used with Safari, to test the various methods. On windows for Firefox, IE and Chrome, accevent was used to listen for the SYS_ALERT event to fire when the text alert was displayed. Also JAWS, and NVDA were used to verify wheter the alert text was announced.
Note: JAWS worked fine with IE for all methods as it does not rely upon the SYS_ALERT event, but NVDA only works in IE with method 4 as it does rely on the SYS_ALERT event.
Comments
Method 3 is clearly the easiest to implement and would generally follow the visual generation and presentation of most alerts. It seems the key is to get Safari to support this method rather than authors using something more convoluted and ‘hackish’.
I’ll test again, but I believe that for repeated alerts (such as a second form validation error) to be presented in JAWS, the role value has to be changed from “alert” or removed altogether and then set back to “alert” before the element is again revealed.
Hi Jared,
I definitely agree, its a matter of getting implementors to fix their software…
After further testing I have discovered an issue with chrome for method 4 which requires a further hack, amd uploading details soon.
Steve,
Have you tried method 3 in combination with setting aria-hidden to true/false? I think (although don’t have the ability to quickly test this) that this works on safari.
–James
Hi James,
Yes i tried using aria-hidden=”true|false”, couldnt get it to work with VoiceOver, if you have any luck give me a yell!
Regardless of current browser support. It sounds like you are advocating option 3 as the ideal solution. Is this correct?
Did you test with Mountain Lion? Would that have the latest version of Safari/VoiceOver? It might also be worth testing with iOS6 to see if there is potential support in the near future.
Hi Ted,
I suppose I am saying that to get it to work with apple devices you have to jump through hoops, I have only tested with latest Mac OS/iOS i have on my machines. I think the best outcome would be for webkit/voiceover to have more robust suppport. To be honest I don’t know if its webkit or VoiceOver thats the problem. It easy to check (using accevent) on windows browsers to see if an alert event is being fired, but I can’t tell if an alert event is being fired in webkit. I am not even sure if webkit implements it that way. It is not a must requirement for browsers to raise a system alert event for the ARIA alert role.
HI again Ted, thinking about it further, the best outcome would be for browsers and AT to recognise changes to content inside ARIA live-regions (alert is a special case live region) consistently. What I mean in practical terms is that live regions should be able to included in the original DOM of the page or inserted after page load and have their
visibility
property changed fromhidden
tovisible
ordisplay:none
todisplay:block
etc, without this having and effect on whether the live-region works or not. Note: I am not saying live regions should work when not visible, but that they should still work if their visibility is changed dynamically. Currently it appears that in IE one must change the content from hidden to visible for it to work, while in Safari the element withrole=alert
must be in the DOM when the page initially loads and cannot be subsequently hidden/shown for it to continue working. There is also some weirdness with chrome. All in all its an unrealistic burden on developers to be expected to deal with. Across browsers it needs to be implemented interoperably i.e. they need to match so the constraints on how and when a live region works as desired, are minimised.Hi Steve, I have to ask why you assume this alert element needs to be created on the fly? It’s easier (for most authors) and better supported in most implementations to just have an existing node in the HTML source (or added to the DOM on load) and change its text via any number of ways, including setting its innerHTML. The inconsistency you’re noticing is to the initialization/registration of new live regions (which is a hard problem that ARIA 1.0 does not entirely solve) and not with changes to existing live regions.
Also, sorry to disappoint everyone, but my read of the spec indicates that method #3 is not a valid implementation of ARIA 1.0. Changing the display of an element does not match insertions, deletions, or text changes.
Clarifying a bit more: Note that item #1 in the Authoring Practices link you mention says “1. Identify the live regions… Note the regions of your page that *will be* live.” but what you’re doing is inserting live regions at the time of the notification. In order for your methods to be entirely supported across all implementations, all rendering engines would have to constantly monitor all DOM nodes in case any of them ever became live regions. This would be prohibitively expensive for performance, which is why you should “identify” those regions to begin with so that rendering engines will know which elements need constant monitoring for future updates. Hope that helps.
Hi James, according to the ARIA implementation guide my reading is that #3 is valid:
For example it says
So for the example:
alert text
I would expect that when its display is changed from hidden to visible the AXLiveRegionChanged event is fired. Additionally in the case of role=alert I would expect a system alert event to be fired (note this is only a SHOULD requirement)
Hi James, good point, In the case of an alert I have made the assumption that its content that will only be displayed contingent upon a user doing something such as making an error or a timeout occuring etc, so it’s not generally going to be in the content or visible in the content unless something occurs and may well be hidden or removed after a sepcificed time period.
Hi James,
So if an element with a role=alert or some other live region, is be present in the DOM, but hidden that is no good? What you you appear to be suggesting is that it needs to be present in the DOM and visible, is that correct?
I think that should possibly work if it was a hidden child node became visible inside an already visible live region. The way you mentioned it here was an element not *inside* the live region that was becoming visible. It *was* the live region becoming visible. I hope we can make this much easier in ARIA 2.0 or IndieUI 1.0.
That’s the way I’d expect it would work best in most implementations, yes. If you like, you could have it positioned offscreen until you visibly “show” it. Part of the issue is that elements with display:none are not exposed at all to most accessibility APIs, and therefore any live region monitoring can’t be done because there is nothing in the API to monitor.
Good work Steve…