Accessibility Examples
Test Start
Lunch Options
-
Thai
-
Subway
-
Jimmy Johns
-
Radio Maria
-
Rainbow Gardens
Drink Options
-
Water
-
Tea
-
Coffee
-
Cola
-
Ginger Ale
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 90 |
|
none |
| Rule 91 |
|
none |
| Rule 92 |
|
none |
| Rule 93 |
|
none |
| Rule 94 |
|
none |
| Rule 95 |
|
none |
| Rule 96 |
|
none |
Calculations
No calculations for test 131
Test Description
- This test implements a simple radio button widget which utilizes aria-activedescendant
Keyboard shortcuts:
* Tab: Move between items.
* Enter or Space: Toggle checked state of the radio button with keyboard focus.
Test Markup
- ARIA 1.0: [aria-activedescendant]
- ARIA 1.0: [aria-checked]
- ARIA 1.0: [aria-labelledby]
- ARIA 1.0: [role="application"]
- ARIA 1.0: [role="presentation"]
- ARIA 1.0: [role="radio"]
- ARIA 1.0: [role="radiogroup"]
User Agent Implementation
No user agent implementation information.
HTML Source Code
<div role="application">
<h3 id="rg1_label">Lunch Options</h3>
<ul class="radiogroup"
id="rg1"
role="radiogroup"
aria-labelledby="rg1_label"
aria-activedescendant="rg1-r4"
tabindex="0";
>
<li id="rg1-r1"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg1-r1_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Thai
</li>
<li id="rg1-r2"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg1-r2_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Subway
</li>
<li id="rg1-r3"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg1-r3_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Jimmy Johns
</li>
<li id="rg1-r4"
tabindex="-1"
role="radio"
aria-checked="true">
<img id="rg1-r4_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-checked.gif" />
Radio Maria
</li>
<li id="rg1-r5"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg1-r5_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Rainbow Gardens
</li>
</ul>
<!-- Start of second Radio Group -->
<h3 id="rg2_label">Drink Options</h3>
<ul id="rg2"
class="radiogroup"
role="radiogroup"
aria-labelledby="rg2_label"
aria-activedescendant=""
tabindex="0"
>
<li id="rg2-r1"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg2-r1_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Water
</li>
<li id="rg2-r2"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg2-r2_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Tea
</li>
<li id="rg2-r3"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg2-r3_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Coffee
</li>
<li id="rg2-r4"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg2-r4_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Cola
</li>
<li id="rg2-r5"
tabindex="-1"
role="radio"
aria-checked="false">
<img id="rg2-r5_img" role="presentation" src="http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif" />
Ginger Ale
</li>
</ul>
</div>
CSS Code
ul.radiogroup {
margin: 0;
padding: 0;
width: 10em;
}
ul.radiogroup li {
padding: 0;
margin: 0;
margin-left: 1em;
padding: 4px;
list-style: none;
width: 9em;
}
ul.radiogroup li:hover {
padding: 2px;
border: gray 2px solid;
}
ul.radiogroup li.selected {
padding: 2px;
border: black 2px solid;
}
.offscreen {
position: absolute;
left: -200em;
top: -20em;
}
Javascript Source Code
$(document).ready(function() {
var group1 = new radioGroup('rg1');
var group2 = new radioGroup('rg2');
}); // end ready
function keyCodes () {
// Define values for keycodes
this.enter = 13;
this.space = 32;
this.left = 37;
this.up = 38;
this.right = 39;
this.down = 40;
}
//
// Function radioGroup() is a class to define an ARIA-enabled radiogroup widget.
//
// This widget attaches to an unordered list and makes each list entry a group
// of radio buttons.
//
// @param (id object) id is the html id of the <ul> to attach to
//
// @return N/A
//
function radioGroup(id) {
var thisObj = this;
///////// define widget properties ///////////////
this.$id = $('#' + id);
// find all list items with a role of radio
this.$buttons = this.$id.find('li').filter('[role=radio]');
// Store the currently checked item
this.$checked = this.$buttons.filter('[aria-checked=true]');
this.checkButton = true; // set to false during ctrl+arrow operations;
if (this.$checked.length > 0) {
this.$active = $('#' + this.$id.attr('aria-activedescendant')); // the active button
}
else {
this.$active = null; // no selected button
}
this.keys = new keyCodes();
///////////// Bind Event handlers ////////////////
this.$buttons.click(function(e) {
return thisObj.handleClick(e, $(this));
});
this.$id.keydown(function(e) {
return thisObj.handleKeyDown(e, $(this));
});
this.$id.keypress(function(e) {
return thisObj.handleKeyPress(e, $(this));
});
this.$id.focus(function(e) {
return thisObj.handleFocus(e, $(this));
});
this.$id.blur(function(e) {
return thisObj.handleBlur(e, $(this));
});
}
//
// Function selectButton() is a member function to select and possibly check a button in the
// radioGroup.
//
// @param ($id object) $id is the jQuery object of the button to select
//
// @return N/A
//
radioGroup.prototype.selectButton = function($id) {
if (this.checkButton == true) {
// checking the button
// remove the checked image from the previously checked button
this.$checked.find('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif');
// set the previous button's aria-checked attribute to false
this.$checked.attr('aria-checked', 'false');
// update the button image
$id.find('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/radio-checked.gif');
// set the new button's aria-checked attribute to true
$id.attr('aria-checked', 'true');
// update the stored $checked object
this.$checked = $id;
}
if (this.$active != null) {
// remove the selected styling from the previous active button
this.$active.removeClass('selected');
}
// give this button the selected class
$id.addClass('selected');
// update the stored $active object
this.$active = $id;
// update the aria-activedescendant property of the group
this.$id.attr('aria-activedescendant', $id.attr('id'));
// reset the checkButton flag - in case it was false
this.checkButton = true;
} // end selectButton()
//
// Function handleClick() is a member function to process keydown events for the radioGroup.
//
// @param (e object) e is the event object
//
// @param ($id object) $is is the jquery object of the triggering element
//
// @return (boolean) Returns false if consuming event; true if propagating
//
radioGroup.prototype.handleClick = function(e, $id) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// do nothing
return true;
}
// select the clicked button
this.selectButton($id);
// give the group focus
this.$id.focus();
e.stopPropagation();
return false;
} // end handleClick()
//
// Function handleKeyDown() is a member function to process keydown events for the radioGroup.
//
// @param (e object) e is the event object
//
// @param ($id object) $is is the jquery object of the triggering element
//
// @return (boolean) Returns false if consuming event; true if propagating
//
radioGroup.prototype.handleKeyDown = function(e, $id) {
if (e.altKey) {
// do nothing
return true;
}
switch (e.keyCode) {
case this.keys.space:
case this.keys.enter: {
if (e.ctrlkey || e.shiftKey) {
// do nothing
return true;
}
// select and check the active the button
this.selectButton(this.$active);
e.stopPropagation();
return false;
}
case this.keys.left:
case this.keys.up: {
var $prev = this.$active.prev(); // the previous button
if (e.shiftKey) {
// do nothing
return true;
}
// if this was the first item
// select the last one in the group.
if (this.$active.index() == 0) {
$prev = this.$buttons.last();
}
if (e.ctrlKey) {
// set checkButton to false so
// focus does not check button
this.checkButton = false;
}
// select the previous button
this.selectButton($prev);
e.stopPropagation();
return false;
}
case this.keys.right:
case this.keys.down: {
var $next = this.$active.next(); // the next button
if (e.shiftKey) {
// do nothing
return true;
}
// if this was the last item,
// select the first one in the group.
if (this.$active.index() == this.$buttons.length - 1) {
$next = this.$buttons.first();
}
if (e.ctrlKey) {
// set checkButton to false so
// focus does not check button
this.checkButton = false;
}
// give the next button focus
this.selectButton($next);
e.stopPropagation();
return false;
}
} // end switch
return true;
} // end handleKeyDown()
//
// Function handleKeyPress() is a member function to process keydown events for the radioGroup.
// This is needed to prevent browsers that process window events on keypress (such as Opera) from
// performing unwanted scrolling of the window, etc.
//
// @param (e object) e is the event object
//
// @param ($id object) $is is the jquery object of the triggering element
//
// @return (boolean) Returns false if consuming event; true if propagating
//
radioGroup.prototype.handleKeyPress = function(e, $id) {
if (e.altKey) {
// do nothing
return true;
}
switch (e.keyCode) {
case this.keys.space:
case this.keys.enter: {
if (e.ctrlKey || e.shiftKey) {
// do nothing
return true;
}
}
case this.keys.left:
case this.keys.up:
case this.keys.right:
case this.keys.down: {
if (e.shiftKey) {
// do nothing
return true;
}
e.stopPropagation();
return false;
}
} // end switch
return true;
} // end handleKeyPress()
//
// Function handleFocus() is a member function to process focus events for the radioGroup.
//
// @param (e object) e is the event object
//
// @param ($id object) $is is the jquery object of the triggering element
//
// @return (boolean) Returns false if consuming event; true if propagating
//
radioGroup.prototype.handleFocus = function(e, $id) {
if (this.$active == null) {
// no previously selected button - select first one
this.selectButton(this.$buttons.first());
}
else {
// select active button
this.selectButton(this.$active);
}
return true;
} // end handleFocus()
//
// Function handleBlur() is a member function to process blur events for the radioGroup.
//
// @param (e object) e is the event object
//
// @param ($id object) $is is the jquery object of the triggering element
//
// @return (boolean) Returns false if consuming event; true if propagating
//
radioGroup.prototype.handleBlur = function(e, $id) {
// remove the focus styling from this buttons
this.$buttons.removeClass('selected');
return true;
} // end handleBlur()