WDCNZ
25 July 2013
<h3>Types of pet</h3>
<ul>
<li><a href="/cat/">cat</a></li>
<li><a href="/dog/">dog</a></li>
<li><a href="/kunekune/">kunekune</a></li>
</ul>
<form>
<fieldset>
<legend>Do you like cats?</legend>
<input type="radio" name="cats" id="yes"
value="yes" checked>
<label for="yes">Yes</label>
<input type="radio" name="cats" id="no"
value="no">
<label for="no">No</label>
</fieldset>
<input type="submit" value="Submit">
</form>
<input type="checkbox" id="dogs"...>
<label for="dogs">Dogs</label>
<div class="checkbox">Dogs</div>
$('.checkbox').on('click', function() {
$(this).toggleClass('checked');
});
.checkbox {
background: white url(../img/checkbox.png)
no-repeat 0 8px;
}
.checkbox.checked {
background-image: url(../img/checkbox-checked.png);
}
No keyboard access.
No role or state information.
role
, e.g. role="navigation"
aria-*
, aria-expanded="true"
It's part of the HTML5 specification.
application
banner
complementary
contentinfo
form
main
navigation
search
article
columnheader
definition
directory
document
group
heading
img
list
listitem
math
note
presentation
region
row
rowheader
separator
toolbar
header
→ “banner” role, if not a child of section
or article
nav
→ “navigation” rolemain
→ “main” roleaside
→ “complementary” rolefooter
→ “contentinfo” role, if not a child of section
or article
alert
alertdialog
button
checkbox
dialog
gridcell
link
log
marquee
menuitem
menuitemcheckbox
menuitemradio
option
progressbar
radio
scrollbar
slider
spinbutton
status
tab
tabpanel
textbox
timer
tooltip
treeitem
combobox
grid
listbox
menu
menubar
radiogroup
tablist
tree
treegrid
button
→ “button” roleinput type="checkbox
→ “checkbox” roleinput type="radio"
→ “radio” role
<a href="#">Link</a>
<a href="#" role="button">Button</a>
<ul>
<li role="button">list item button</li>
</ul>
aria-autocomplete
aria-checked
(state)aria-disabled
(state)aria-expanded
(state)aria-haspopup
aria-hidden
(state)aria-invalid
(state)aria-label
aria-level
aria-multiline
aria-multiselectable
aria-orientation
aria-pressed
(state)aria-readonly
aria-required
aria-selected
(state)aria-sort
aria-valuemax
aria-valuemin
aria-valuenow
aria-valuetext
aria-atomic
aria-busy
(state)aria-live
aria-relevant
aria-dropeffect
aria-grabbed
(state)aria-activedescendant
aria-controls
aria-describedby
aria-flowto
aria-labelledby
aria-owns
aria-posinset
aria-setsize
http://www.w3.org/TR/wai-aria/states_and_properties#state_prop_taxonomy
tabindex="0"
tabindex="-1"
tabindex="1+"
(Avoid)role="presentation"
Removes an element's default semantics.
<h3>Level 3 heading</h3>
<h3 role="presentation">Not a heading</h3>
<table>
<caption>Layout table</caption>
<tr><td>Name:</td><td>Jonas Salk</td></tr>
<tr><td>Discovery:</td><td>Polio vaccine</td></tr>
</table>
Name: | Jonas Salk |
Discovery: | Polio vaccine |
<table role="presentation">
<caption>Not a table</caption>
<tr><td>Name:</td><td>Jonas Salk</td></tr>
<tr><td>Discovery:</td><td>Polio vaccine</td></tr>
</table>
Name: | Jonas Salk |
Discovery: | Polio vaccine |
Don't do this!
It won't work anyway.
<a href="#" role="presentation">Still a link!</a>
<button role="presentation">Still a button!</a>
<div class="checkbox">Dogs</div>
$('.checkbox').on('click', function() {
$(this).toggleClass('checked');
});
.checkbox {
background: white url(../img/checkbox.png)
no-repeat 0 8px;
}
.checkbox.checked {
background-image: url(../img/checkbox-checked.png);
}
No keyboard access.
No role or state information.
tabindex="0"
<div class="checkbox" tabindex="0">Dogs</div>
$('.checkbox').on('click', function() {
$(this).toggleClass('checked');
});
$('.checkbox').keydown(function(e) {
if (e.which == 32) {
$(this).click();
}
});
Still no role or state information.
role="checkbox"
and @aria-checked
<div class="checkbox" tabindex="0"
role="checkbox" aria-checked="false">Dogs</div>
aria-checked
$('.checkbox').on('click', function() {
if ($(this).attr('aria-checked') == 'false') {
$(this).attr('aria-checked', 'true');
} else {
$(this).attr('aria-checked', 'false');
}
});
$('.checkbox').keydown(function(e) {
if (e.which == 32) {
$(this).click();
}
});
Role and state provided.
input type="range"
<label for="slider">
Percentage (multiples of 10)
</label>
<input id="slider" type="range"
min="0" max="100" step="10" value="0">
Supported in Opera, Safari, Chrome, IE10,
and FF23 (6 August 2013).
Otherwise falls back to input type="text"
.
<div>Percentage (multiples of 10)</div>
<div class="slider-widget">
<div id="slider" tabindex="0"></div>
</div>
Keyboard accessible with tabindex="0"
and handlers for left arrow and right arrow.
No programmatic label.
No role or state information.
role="slider"
aria-labelledby
aria-valuenow
aria-valuetext
<div id="slider-label">
Percentage (multiples of 10)
</div>
<div class="slider-widget">
<div id="slider" tabindex="0" role="slider"
aria-labelledby="slider-label"
aria-valuemin="0" aria-valuemax="10"
aria-valuenow="0" aria-valuetext="0%"></div>
</div>
Label, role and state provided.
aria-labelledby
<div id="label">Date</div>
<input type="text" aria-labelledby="label format">
<span id="format">DD-MM-YYYY</span>
aria-label
<nav role="navigation" aria-label="Main menu">
<ul>
…
</ul>
</nav>
<button aria-label="Close">X</button>
aria-describedby
<label for="comment">Leave a comment</label>
<textarea id="comment" aria-describedby="notice">
</textarea>
<p id="notice">Note: Your comment may be published.</p>
Note: Your comment may be published.
<ul>
<li><a href="#cat">Cat</a></li>
<li><a href="#dog">Dog</a></li>
<li><a href="#horse">Horse</a></li>
</ul>
<div>
<h3 id="cat">Man with cat</h2>
...
</div>
<div>
<h3 id="dog">Man with dog</h2>
...
</div>
<div>
<h3 id="horse">Horse and bridal party</h2>
...
</div>
<ul class="tablist">
<li class="current"><a href="#cat">Cat</a></li>
<li><a href="#dog">Dog</a></li>
<li><a href="#horse">Horse</a></li>
</ul>
<div class="tabpanel" style="display: block;">
<h3 id="cat">Man with cat</h2>
...
</div>
<div class="tabpanel" style="display: none;">
<h3 id="dog">Man with dog</h2>
...
</div>
<div class="tabpanel" style="display: none;">
<h3 id="horse">Horse and bridal party</h2>
...
</div>
No role or state information provided.
tabindex
<ul role="tablist">
<li role="presentation">
<a role="tab" aria-controls="panel-cat"
aria-selected="true" tabindex="0"
href="#cat">Cat</a>
</li>
<li role="presentation">
<a role="tab" aria-controls="panel-dog"
aria-selected="false" tabindex="-1"
href="#dog">Dog</a>
</li>
<li role="presentation">
<a role="tab" aria-controls="panel-horse"
aria-selected="false" tabindex="-1"
href="#horse">Horse</a>
</li>
</ul>
<div id="panel-cat" role="tabpanel"
aria-labelledby="cat">
<h3 id="cat">Man with cat</h3>
…
</div>
<div id="panel-dog" role="tabpanel"
aria-labelledby="dog">
<h3 id="dog">Man with dog</h3>
…
</div>
<div id="panel-horse" role="tabpanel"
aria-labelledby="horse">
<h3 id="horse">
Horse and bridal party
</h3>
…
</div>
aria-live="assertive/polite/off"
aria-atomic="true/false"
aria-relevant="additions/removals/text/all"
*Click "Users online" heading below to start/stop demo.
<h3>Users online</h3>
<ul aria-live="polite" aria-relevant="additions removals">
</ul>
role="alert"
Default is aria-live="assertive"
.
Make someone happy with this stunning 87 piece bracelet.
All yours for just $24.99.
role="application"
role="menu"
role="menubar"
role="tree"
role="grid"
role="treegrid"
role="alertdialog"
role="spinbutton"
role="progressbar"
aria-hidden
aria-required
aria-expanded
aria-activedescendant
aria-haspopup
aria-dropeffect
aria-invalid
aria-pressed
aria-level
...and more
Browser and screen reader support is improving all the time.
Good support for structural roles and many common widgets and attributes.
Still lots of variability in browser and screen reader support,
especially for complex widgets.
Do the research, as you do…
Use native HTML elements and attributes as much as possible.
Don't override native HTML semantics, unless absolutely necessary.