Accessibility Examples
Test Start
Live Region 1: Simple Counter
:
:
:
:
:
XXX
Live Region 2: Text Log
:
:
:
:
Test End
Rule References
| Rule | Pass IDs | Fail IDs |
|---|---|---|
| Rule 84 |
|
none |
| Rule 85 |
|
none |
| Rule 86 |
|
none |
| Rule 87 |
|
none |
| Rule 88 |
|
none |
| Rule 92 |
|
none |
| Rule 93 |
|
none |
| Rule 94 |
|
none |
| Rule 95 |
|
none |
Calculations
No calculations for test 126
Test Description
- This test implements a simple aria-live region with a counter and log
Keyboard shortcuts:
* Tab: Move between controls
* Enter or space: Toggle region updates
Test Markup
- ARIA 1.0: [aria-activedescendant]
- ARIA 1.0: [aria-atomic]
- ARIA 1.0: [aria-controls]
- ARIA 1.0: [aria-labelledby]
- ARIA 1.0: [aria-live]
- ARIA 1.0: [aria-pressed]
- ARIA 1.0: [aria-relevant]
- ARIA 1.0: [aria-selected]
- ARIA 1.0: [role="application"]
- ARIA 1.0: [role="log"]
- ARIA 1.0: [role="option"]
- ARIA 1.0: [role="timer"]
User Agent Implementation
No user agent implementation information.
HTML Source Code
<div id="application" role="application">
<div class="controls">
<h2>Live Region 1: Simple Counter</h2>
<p><label id="time1Label" for="time1">Change Interval (seconds)</label>:
<select id="time1" aria-labelledby="time1Label" aria-activedescendant="time1_opt1">
<option id="time1_opt1" role="option" aria-selected="true" selected>1</option>
<option id="time1_opt2" role="option" aria-selected="false">2</option>
<option id="time1_opt3" role="option" aria-selected="false">3</option>
<option id="time1_opt4" role="option" aria-selected="false">4</option>
<option id="time1_opt5" role="option" aria-selected="false">5</option>
<option id="time1_opt6" role="option" aria-selected="false">6</option>
<option id="time1_opt7" role="option" aria-selected="false">7</option>
<option id="time1_opt8" role="option" aria-selected="false">8</option>
<option id="time1_opt9" role="option" aria-selected="false">9</option>
<option id="time1_opt10" role="option" aria-selected="false">10</option>
</select>
</p>
<p><label id="politeness1Label" for="politeness1">Live Property Value</label>:
<select id="politeness1" aria-labelledby="politeness1Label" aria-activedescendant="polite1_opt3">
<option id="polite1_opt1" role="option" aria-selected="false">off</option>
<option id="polite1_opt2" role="option" aria-selected="false">polite</option>
<option id="polite1_opt3" role="option" aria-selected="true" selected>assertive</option>
<option id="polite1_opt4" role="option" aria-selected="false">rude</option>
</select>
</p>
<p><label id="atomic1Label" for="atomic1">Atomic Property Value</label>:
<select id="atomic1" aria-labelledby="atomic1Label" aria-activedescendant="atomic1_opt1">
<option id="atomic1_opt1" role="option" aria-selected="true" selected>true</option>
<option id="atomic1_opt2" role="option" aria-selected="false">false</option>
</select>
</p>
<p><label id="relevant1Label" for="relevant1">Relevant Property Value</label>:
<select id="relevant1" aria-labelledby="relevant1Label" aria-activedescendant="relevant1_opt4">
<option id="relevant1_opt1" role="option" aria-selected="false">additions</option>
<option id="relevant1_opt2" role="option" aria-selected="false">removals</option>
<option id="relevant1_opt3" role="option" aria-selected="false">text</option>
<option id="relevant1_opt4" role="option" aria-selected="true" selected>all</option>
</select>
</p>
<button id="rgn1_button" aria-controls="liveregion1" aria-pressed="false">Start Counter</button>
</div>
<div class="example">
<div id="region1Container">
<label id="live1Label" for="liveregion1">Changing value</label>:
<div id="liveregion1"
class="region"
role="timer"
aria-labelledby="live1Label"
aria-live="assertive"
aria-atomic="true"
aria-relevant="all">XXX
</div>
</div>
</div>
<div class="controls">
<h2>Live Region 2: Text Log</h2>
<p><label id="time2Label" for="time2">Change Interval (in seconds)</label>:
<select id="time2" aria-labelledby-"time2Label" aria-activedescendant="time2_opt5">
<option id="time2_opt1" role="option" aria-selected="false">1</option>
<option id="time2_opt2" role="option" aria-selected="false">2</option>
<option id="time2_opt3" role="option" aria-selected="false">3</option>
<option id="time2_opt4" role="option" aria-selected="false">4</option>
<option id="time2_opt5" role="option" aria-selected="true" selected>5</option>
<option id="time2_opt6" role="option" aria-selected="false">6</option>
<option id="time2_opt7" role="option" aria-selected="false">7</option>
<option id="time2_opt8" role="option" aria-selected="false">8</option>
<option id="time2_opt9" role="option" aria-selected="false">9</option>
<option id="time2_opt10" role="option" aria-selected="false">10</option>
</select>
</p>
<p><label id="politeness2Label" for="politeness2">Live Property Value</label>:
<select id="politeness2" aria-labelledby="politeness2Label" aria-activedescendant="polite2_opt2">
<option id="polite2_opt1" role="option" aria-selected="false">off</option>
<option id="polite2_opt2" role="option" aria-selected="true" selected>polite</option>
<option id="polite2_opt3" role="option" aria-selected="false">assertive</option>
<option id="polite2_opt4" role="option" aria-selected="false">rude</option>
</select>
</p>
<p><label id="atomic2Label" for="atomic2">Atomic Property Value</label>:
<select id="atomic2" aria-labelledby="atomic2Label" aria-activedescendant="atomic2_opt2">
<option id="atomic2_opt1" role="option" aria-selected="false">true</option>
<option id="atomic2_opt2" role="option" aria-selected="true" selected>false</option>
</select>
</p>
<p><label id="relevant2Label" for="relevant2">Relevant Property Value</label>:
<select id="relevant2" aria-labelledby="relevant2Label" aria-activedescendant="relevant2_opt1">
<option id="relevant2_opt1" role="option" aria-selected="true" selected>additions</option>
<option id="relevant2_opt2" role="option" aria-selected="false">removals</option>
<option id="relevant2_opt3" role="option" aria-selected="false">text</option>
<option id="relevant2_opt4" role="option" aria-selected="false">all</option>
</select>
</p>
<button id="rgn2_button" aria-controls="liveregion2" aria-pressed="false">Start Log</button>
</div>
<div class="example">
<label id="region2Label" for="liveregion2">Log Text</label>
<div id="liveregion2"
class="region"
role="log"
aria-labelledby="region2Label"
aria-live="polite"
aria-atomic="false"
aria-relevant="additions">
</div>
</div>
</div>
CSS Code
div#application {
height: 30em;
}
div.controls {
margin-left: 10px;
padding: 5px 10px;
width: 21em;
float: left;
clear: both;
border-bottom: 1px solid #008;
}
button,
select {
float: right;
}
h2 {
clear: both;
}
div.example {
margin-top: 50px;
margin-left: 30px;
width: 22em;
float: left;
}
div#region1Container {
margin-left: 4em;
padding: 10px;
width: 11em;
height: 1.6em;
float: left;
}
div#region1Container label {
padding-top: 10px;
font-weight: bold;
}
div#liveregion1 {
margin: 0;
padding: 2px 5px;
float: right;
width: 2em;
text-align: right;
border: 1px solid black;
}
label#region2Label {
font-weight: bold;
font-size: 1.2em;
}
div#liveregion2 {
padding: 2px 5px;
width: 22em;
border: 1px solid black;
height: 9em;
overflow: auto;
}
Javascript Source Code
var g_msg1 = {
msgArray: new Array("0","1","2","3","4","5","6","7","8","9"),
index: 0
};
var g_msg2 = {
msgArray: new Array(
"The birch canoe slid on the smooth planks.",
"Glue the sheet to the dark blue background.",
"It's easy to tell the depth of a well.",
"These days a chicken leg is a rare dish.",
"Rice is often served in round bowls.",
"The juice of lemons makes fine punch.",
"The box was thrown beside the parked truck.",
"The hogs were fed chopped corn and garbage.",
"Four hours of steady work faced us.",
"Large size in stockings is hard to sell."
),
index: 0
};
var g_msg1index = 0;
var g_msg2index = 0;
$(document).ready(function() {
var live1 = new liveRegion('liveregion1', function() {updateRegion('liveregion1', g_msg1, false);}, 1000, true);
var live2 = new liveRegion('liveregion2', function() {updateRegion('liveregion2', g_msg2, true);}, 5000, true);
var rgn1Stopped = true;
var rgn2Stopped = true;
// initialize the selects to ensure that their selected values match the markup
init();
///////////////// Bind event handlers for live1 controls //////////////////////////
// bind a change event handler for the interval select
$('#time1').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the interval
live1.setInterval($newItem.text()*1000);
e.stopPropagation();
return false;
});
// bind a change event handler for the politeness select
$('#politeness1').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the politeness
live1.setPoliteness($newItem.text());
e.stopPropagation();
return false;
});
// bind a change event handler for the atomic select
$('#atomic1').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the politeness
live1.setAtomic($newItem.text());
e.stopPropagation();
return false;
});
// bind a change event handler for the update relevance select
$('#relevant1').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the update revelance setting
live1.setRelevant($newItem.text());
e.stopPropagation();
return false;
});
// bind a click handler for the start/stop button
$('#rgn1_button').click(function(e) {
// toggle the region updates
live1.toggleUpdates();
if (rgn1Stopped == false) {
$('#liveregion1').html('XXX');
$(this).html('Start Counter');
rgn1Stopped = true;
}
else {
$(this).html('Stop Counter');
rgn1Stopped = false;
}
e.stopImmediatePropagation();
return false;
});
///////////////// Bind event handlers for live2 controls //////////////////////////
$('#time2').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the interval
live2.setInterval($newItem.text()*1000);
e.stopPropagation();
return false;
});
// bind a change event handler for the politeness select
$('#politeness2').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the politeness
live2.setPoliteness($newItem.text());
e.stopPropagation();
return false;
});
// bind a change event handler for the atomic select
$('#atomic2').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the politeness
live2.setAtomic($newItem.text());
e.stopPropagation();
return false;
});
// bind a change event handler for the update relevance select
$('#relevant2').change(function(e) {
// select the new item
var $newItem = selectItem($(this), $(this).find('option'), $(this).val());
// set the update revelance setting
live2.setRelevant($newItem.text());
e.stopPropagation();
return false;
});
// bind a click handler for the start/stop button
$('#rgn2_button').click(function(e) {
// toggle the region updates
live2.toggleUpdates();
if (rgn2Stopped == false) {
$(this).html('Start Log');
rgn2Stopped = true;
}
else {
rgn2Stopped = false;
$(this).html('Stop Log');
}
e.stopImmediatePropagation();
return false;
});
}); // end ready()
//
// Function init() is a function to initialize the select elements to match their activedescendant values. This
// ensures that any page reloads do not introduce erroneous aria attribute values
function init() {
var elems = new Array('time1', 'politeness1', 'atomic1', 'relevant1', 'time2', 'politeness2', 'atomic2', 'relevant2');
var $id = null;
var val = null;
for (ndx in elems) {
// get the jQuery object of select to set
$id = $('#' + elems[ndx]);
// get the value of the active descendant
val = $('#' + $id.attr('aria-activedescendant')).text();
// set the value of the select
$id.val(val);
}
} // end init()
//
// Function selectItem() is a function to iterate through an option list to find a new option and select it.
// The function also updates the aria-seleced attribute of the items.
//
// @param ($select object) $select is the jquery object of the select that the option list is part of.
//
// @param ($list object) $list is the list of options to iterate through.
//
// @param (val string) val is the value to find in the list.
//
// @return (object) returns the jquery object of the new item selected. Returns NULL if not found.
//
function selectItem($select, $list, val) {
var $prevItem = $('#' + $select.attr('aria-activedescendant'));
var $newItem = null;
// find the list item associated with the new value
$list.each(function() {
if ($(this).text() == val) {
$newItem = $(this);
}
});
if ($newItem == null) {
// no new item found
return null;
}
// set the aria-selected attribute to false for the previously selected item
$prevItem.attr('aria-selected', 'false');
// set the aria-selected attribute to true for the new item
$newItem.attr('aria-selected', 'true')
// update the active descendent of the select
$select.attr('aria-activedescendant', $newItem.attr('id'));
// return the new item selected
return $newItem;
} // end selectItem()
//
// The function updateRegion() is called by a liveRegion timer to updates the live region
// with new content based on the passed messageArray.
//
// @param (live_region object) LiveRegion is the liveRegion widget object
//
// @param (msgArray array) msgArray is an array of messages to use for the update
//
// @param (append boolean) append is true if messages should be appended, false if message should
// replace live region content
//
// @return N/A
//
function updateRegion (region, msgObj, append) {
var $regionID = $('#' + region);
var msg = '';
if (msgObj.index == msgObj.msgArray.length) {
// We've reached the end of the array, reset the index.
msgObj.index = 0;
// clear the region
$regionID.empty();
}
if (append == false) {
msg = msgObj.msgArray[msgObj.index];
// messages should replace live region contents.
// Empty the live region
$regionID.empty();
}
else {
msg = msgObj.msgArray[msgObj.index] + '<br/>';
}
// append the new message to the live region
$regionID.append(msg);
if (append == true) {
$regionID.scrollTop($regionID.attr('scrollHeight'));
}
// increment the message index
msgObj.index++;
}