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 |
Calculations
No calculations for test 132
Test Description
- This test implements a simple radio button widget which utilizes background images for visual state
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-checked]
- ARIA 1.0: [aria-labelledby]
- ARIA 1.0: [role="application"]
- ARIA 1.0: [role="radio"]
- ARIA 1.0: [role="radiogroup"]
User Agent Implementation
No user agent implementation information.
HTML Source Code
<div id="application" role="application">
<h3 id="rg1_label">Lunch Options</h3>
<ul class="radiogroup"
id="rg1"
role="radiogroup"
aria-labelledby="rg1_label"
>
<li id="r1"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Thai
</li>
<li id="r2"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Subway
</li>
<li id="r3"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Jimmy Johns
</li>
<li id="r4"
class="checked"
tabindex="0"
role="radio"
aria-checked="true">
Radio Maria
</li>
<li id="r5"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
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"
>
<li id="r6"
class="unchecked"
tabindex="0"
role="radio"
aria-checked="false">
Water
</li>
<li id="r7"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Tea
</li>
<li id="r8"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Coffee
</li>
<li id="r9"
class="unchecked"
tabindex="-1"
role="radio"
aria-checked="false">
Cola
</li>
<li id="r10"
class="unchecked"
class="last"
tabindex="0"
role="radio"
aria-checked="false">
Ginger Ale
</li>
</ul>
</div>
CSS Code
ul.radiogroup {
margin: 0;
padding: 0;
width: 10em;
}
ul.radiogroup li {
margin: 0;
margin-left: 1em;
padding: 4px;
padding-left: 20px;
list-style: none;
width: 9em;
}
ul.radiogroup li:hover {
padding: 2px 18px;
background-position: 2px 4px;
border: gray 2px solid;
}
ul.radiogroup li.selected {
padding: 2px 18px;
background-position: 2px 4px;
border: black 2px solid;
}
.offscreen {
position: absolute;
left: -200em;
top: -20em;
}
.checked {
background: url('http://www.oaa-acessibility.org/media/testsuite/images/radio-checked.gif') no-repeat 4px 6px;
}
.unchecked {
background: url('http://www.oaa-acessibility.org/media/testsuite/images/radio-unchecked.gif') no-repeat 4px 6px;
}
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;
this.$active = null; // the selected button (may not be checked)
this.keys = new keyCodes();
///////////// Bind Event handlers ////////////////
this.$buttons.click(function(e) {
return thisObj.handleClick(e, $(this));
});
this.$buttons.keydown(function(e) {
return thisObj.handleKeyDown(e, $(this));
});
this.$buttons.keypress(function(e) {
return thisObj.handleKeyPress(e, $(this));
});
this.$buttons.focus(function(e) {
return thisObj.handleFocus(e, $(this));
});
this.$buttons.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.removeClass('checked').addClass('unchecked');
// set the previous button's aria-checked attribute to false
this.$checked.attr('aria-checked', 'false');
// update the button image
$id.removeClass('unchecked').addClass('checked');
// set the new button's aria-checked attribute to true
$id.attr('aria-checked', 'true');
if (this.$checked.length == 0) { // no previously checked group buttons
// the first and last items in the group will have
// tabindex=0. Remove them both from the tab order.
this.$buttons.first().attr('tabindex', '-1');
this.$buttons.last().attr('tabindex', '-1');
}
else {
// remove the previously checked item from
// the tab order
this.$checked.attr('tabindex', '-1');
}
// Place this button in the tab order
$id.attr('tabindex', '0');
// update the stored $checked object
this.$checked = $id;
}
// reset the checkButton flag - in case it was false
this.checkButton = true;
// update the stored $active object
this.$active = $id;
// give this button the selected class
$id.addClass('selected');
} // end selectButton()
//
// 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.handleClick = function(e, $id) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// do nothing
return true;
}
// simply consume the event - browser calls 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 button
this.selectButton($id);
e.stopPropagation();
return false;
}
case this.keys.left:
case this.keys.up: {
var $prev = $id.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 ($id.index() == 0) {
$prev = this.$buttons.last();
}
if (e.ctrlKey) {
// set checkButton to false so
// focus does not check button
this.checkButton = false;
}
// give the previous button focus
$prev[0].focus();
e.stopPropagation();
return false;
}
case this.keys.right:
case this.keys.down: {
var $next = $id.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 ($id.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
$next[0].focus();
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) {
// Do button selection processing
this.selectButton($id);
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
$id.removeClass('selected');
return true;
} // end handleBlur()