ARIA Non-Modal Dialog Example
Tab to the more info link and activate it.
Notes:
- Although the dialog is non model the role alertdialog (and not dialog) so that contents of alert dialogs will be read automatically by the screen reader when the dialog opens.
- When the dialog is opened, focus is given to the dialog header.
- Both the activation link and the close link are simple links which are in the tabbing order and keyboard accessible keyboard
- When the dialog closes the focus is returned to the link that activated it.
- F6 will move focus between the application and an open non-model dialog. (Although it is non modal, you can not just tab out of the dialog.)
- The mouse user may click on either the application or the dialog to change focus between the two.
- Aria-describedby attribute identifies the message of an alertdialog. Aria-labelledby identifies the header.
For more best practice patterns see non-modal dialogs.
Step by Step: How we made the dialog (tutorial)
In the discussion on ARIA, we discussed 5 steps with ARIA. They are:
- Alert users to what each elements is: Their role (such as checkbox).
- Alert users to their properties and important relationships (such as disabled, required,and other labels).
- Alert users to what each element is doing: The state (such as checked).
- Alert users to changes in their state.
- Make sure widgets are keyboard accessible and focus works predictably. Events can be triggered though the keyboard, and it should be intuitive to the user. All controls should receive focus via tabbing though the keyboard.
Step 1: Set roles.
Our buttons are HTML standard form controls so we do not need form control roles as well. The DIV that contained the dialog content however needs a role as the tag "DIV" does not describe how it behaves.
We chose the role alertdialogas that is closer to the behavior it will have. It is a type of dialog that contains an alert message, where initial focus goes to an element within the dialog (in our case the close button). Also the contents of alert dialogs will are read automatically by the screen reader when the dialog opens.
Step 2: Set properties and important relationships
The dialog contents are all rapped inside the alertdialog role so that they belong together is implied in the code or DOM. So the groups are clear. However the specification for alertdialog seas that authors should use aria-describedby on an alertdialog to point to the alert message element in the dialog. We should also give it a label.
So the HTML for out dialog looks something like this:<div class="bubble" aria-labelledby="bubblehead" role="alertdialog" id="bubble1" aria-describedby="dialogtext">
<p > <a class="close" href="#" id="closebtn1" >Close</a></p>
<h3 id="bubblehead">More info</h3>
<div id="dialogtext">The Username is sometimes called User ID. </div></div>
Note that it is always worth looking at any requirements such as required states, and supported states for your roles before deciding what properties and states you need.
Step 3: Set the initial states
A good rule of thumb is elements that change how they look often have states that can change. The dialog changes in that it goes from being visible to invisible. So we are going to use aria-hidden="true" on the dialog initially and change it's value when it is shown.
We also use CSS selectors, to show and hide the dialog based on the aria-hidden value. Now I do not need to change their CSS class in the code, only the value of aria-hidden.
.bubble[aria-hidden='true'] {
display: none;
}
.bubble[aria-hidden='false'] {
display:block ;
}
Note that to make the content degrade gracefully, we want the dialog to be open if scripts are not working. So we set aria-hidden='false'
in the HTML, and set aria-hidden='true'
in the document ready function. This way if scripts are working the dialog is hidden, but if scripts are not supported the user will still get the content.
$(document).ready(function(){
$("#bubble1").attr("aria-hidden","true");
A word about backward compatibility....
Unfortunately IE 9 does not support the CSS selectors above. (IE 10 does support them.) So to make this work with older browser I added a class hidden:
.hidden {display:none;}
In the script, whenever I set aria-hidden = "true"
in the script, I also added the class hidden to the same selector:
$("....").addClass("hidden");
I also removed it when I set aria-hidden = "false"
:
$("...").removeClass("hidden");
This makes the script much more robust in older browsers.
Step 4: Set changes in state.
We discussed above that the dialog uses the aria state of aria-hidden, and we are using CSS selectors so that whenever aria-hidden='true'
the dialog will be hidden and when aria-hidden='false'
the dialog will be visible.
In the code we have a function to open the dialog by changing the values of aria-hidden.
$("#bubble1").attr("aria-hidden","false");
Step 4: Manage focus and keyboard accessibility.
Both the focus and keyboard accessibility needs to be managed.
Firstly lets deal with the keyboard accessibility and make sure our jQuery selectors are device independent. In the code we have used mouse events such as "click()" to trigger the button function such as :
$("a#bubble-associate1").click(function()
We need to add events as well for people who can not use a mouse.
The following function gives keyboard accessibility, so that pressing enter (key-code 13) is the same as clicking with a mouse.
$("a#bubble-associate1']").keydown(function(ev) {
if (ev.which ==13) {
$(this).click()
}
});
For this design pattern the focus should move to the dialog header when the dialog is opened. Altogether the code to open the dialog looks like this:
$("a#bubble-associate1").click(function(){
$("#bubble1").attr("aria-hidden","false");
$("#bubblehead").focus();
ev.preventDefault();
});
Note: We also need to set tabindex=1 in the dialog headerso that it can accept the focus.
<h3 id="bubblehead" tabindex="0">More info</h3>
Pressing the enter should close the dialog and return the focus, and everything else keeps the focus on the "close" button. (Triggering on the keydown event)
switch(ev.which)
{ case 27:
$("#bubble1").attr("aria-hidden","true");
$("#bubble-associate1").focus();
ev.preventDefault();
break;
case 117:
$("#bubble-associate1").focus();
ev.preventDefault();
break;
}
The "esc" key will also close the dialog on the keypress event. Shift + F6 should return the focus and not close it.
switch(ev.which)
{
case 13:
$("#bubble1").attr("aria-hidden","true");
$("#bubble-associate1").focus();
ev.preventDefault();
return false;
break;
default:
$("a#closebtn1").focus();
ev.preventDefault();
break;
}
Author: Lisa Seeman