Government Digital Service (GDS)
HTML interactive elements are keyboard supported by default
w3.org/tr/html52/interactive-elements.html#interactive-elements
a element<a href="...">...</a>
button element<button>...</button>
select element<select>...</select>
The tab order follows the DOM order of interactive elements
<div>
<button>1</button>
<button>2</button>
<button>3</button>
</div>
<div style="display: flex;">
<button style="order: 3;">1</button>
<button style="order: 2;">2</button>
<button style="order: 1;">3</button>
</div>
tabindex attributetabindex="0" attribute<div>
<button>1</button>
<span tabindex="0" class="button">2</span>
<button>3</button>
</div>
tabindex="0" demotabindex="-1" attribute<div>
<button>1</button>
<button tabindex="-1">2</button>
<button>3</button>
</div>
tabindex="-1" demo.focus() method<div id="dialog" tabindex="-1">...</div>
var dialog = getElementById("dialog");
dialog.focus();
tabindex="N" attribute<div>
<button tabindex="3">1</button>
<button tabindex="2">2</button>
<button tabindex="1">3</button>
</div>
tabindex="N" demoGo to:
alphagov.github.io/a11y-dev-workshop/exercise1
An element's role describes its purpose
header element<header>...</header>
footer element<footer>...</footer>
main element<main>...</main>
nav element<nav>...</nav>
ul element<ul>...</ul>
li element<ul>
<li>...</li>
<li>...</li>
</ul>
h1 element<h1>...</h1>
select element<select>...</select>
input type="text" element<input type="text">
input type="password" element<input type="password">
input type="checkbox" element<input type="checkbox">
An element may be in a different state, or have different properties
h1 element<h1>...</h1>
h2 element<h2>...</h2>
checked attribute<input type="checkbox" checked>
disabled attribute<button disabled>...</button>
Go to:
alphagov.github.io/a11y-dev-workshop/exercise2
<div class="toolbar">
<span class="button">Bold</span><span class="button">Italic</span>...
</div>
Attributes that polyfill missing role, name, and state information for screen readers
role attribute70+ roles, including:
aria- attributes45+ states and properties, including:
aria-invalid, aria-requiredaria-pressed, aria-expandedaria-controls, aria-ownsIf you can use a native HTML element or attribute with the semantics and behaviour you require... then do so
Do not change native semantics, unless you really have to
role attribute<button role="heading" aria-level="1">Foo</button>
All interactive controls must be usable with a keyboard
<a href="#here" id="button" role="button">...</a>
var button = document.getElementById('button');
button.addEventListener('keydown', function(event) {
    if (event.keyCode == 13) {
        doSomething();
    }
});
<span id="button" role="button" tabindex="0">...</span>
var button = document.getElementById('button');
button.addEventListener('keydown', function(event) {
    if (event.keyCode == 13 || event.keyCode == 32) {
        doSomething();
    }
});
application role<body role="application">...</body>
Stops screen reader commands from working and hands navigation back to the browser
Other ARIA roles trigger applications mode, including:
Do not use role="presentation" or aria-hidden="true" on visible and focusable elements
role="presentation" attribute<button role="presentation">Foo</button>
Removes the element's semantics (but not its content)
table element<table role="presentation">...</table>
Useful workaround for layout tables
role="none" attribute<button role="none">Foo</button>
Introduced in ARIA 1.1 as a synonym for role="presentation"
aria-hidden attribute<button aria-hidden="true">Foo</button>
Removes the element from the accessibility tree
hidden attribute<nav hidden>...</nav>
Hides content from everyone
display:none; property<div id="reveal" style="display:none;">...</div>
Hides content from everyone, unless CSS is disabled
All interactive elements must have an accessible name
Identifies an instance of an element within an interface
Provides additional descriptive information about an element
a element<a href="https://gov.uk">Gov.UK</a>
alt attribute<img src="logo.svg" alt="Firefox logo">
label element<input type="checkbox" id="uk">
<label for="uk">I live in the UK</label>
fieldset and legend elements<fieldset>
<legend>Do you live in the UK?</legend>
<input type="checkbox" name="uk" id="yes">
<label for="yes">Yes</label>
<input type="radio" name="uk" id="no">
<label for="no">No</label>
</fieldset>
aria-label attribute<button aria-label="Search"><span class="icon"></span></button>
aria-labelledby attribute<section aria-labelledby="services">
<h2 id="services">Services and information</h2>
...
</section>
aria-describedby attribute<label for="tel">Your phone number</label>
<input type="text id="tel" aria-describedby="desc">
<p id="desc">Enter your phone number with no spaces</p>
Browser algorithm for calculating accessible names and descriptions
w3.org/tr/accname-aam-1.1/
For each example, identify the element's accessible name and/or description
<button>Edit your answer</button>
<button aria-label="Edit your address">Edit your answer</button>
<label>Email address</label>
<input type="email" aria-describedby="desc">
<p id="desc">We will send confirmation to this email address</p>
<img src="stock.jpg" alt="">
<img src="browser-stats.svg" alt="Browser statistics chart"
aria-describedby="browser-stats-desc">
<div id="browser-stats-desc">
<p>A pie chart showing the percentage of visitors to Gov.UK using different browsers...</p>
</div>
<button>Edit your answer</button>
Accessible name is "Edit your answer".
<button>Edit your answer</button>
<button aria-label="Edit your address">Edit your answer</button>
Accessible name is "Edit your address".
<button aria-label="Edit your address">Edit your answer</button>
<label>Email address</label>
<input type="email" aria-describedby="desc">
<p id="desc">We will send confirmation to this email address</p>
No accessible name.
<label>Email address</label>
<input type="email" aria-describedby="desc">
<p id="desc">We will send confirmation to this email address</p>
<img src="stock.jpg" alt="">
No accessible name.
<img src="stock.jpg" alt="">
<img src="browser-stats.svg" alt="Browser statistics chart"
aria-describedby="browser-stats-desc">
<div id="browser-stats-desc">
<p>A pie chart showing the percentage of visitors to Gov.UK using different browsers...</p>
</div>
Accessible name is "Browser statistics chart. Accessible description is "Pie chart showing...".
<img src="browser-stats.svg" alt="Browser statistics chart"
aria-describedby="browser-stats-desc">
<div id="browser-stats-desc">
<p>A pie chart showing the percentage of visitors to Gov.UK using different browsers...</p>
</div>
input type="checkbox" element<input type="checkbox" checked id="tc">
<label for="tc">Accept terms and conditions</label>
Used by ATs to query accessibility information
smashingmagazine.com/2015/03/web-accessibility-with-accessibility-api/
Define how role, state, properties, and keyboard focus are handled in the browser
An element may be supported in a browser, but not accessibility supported
Go to:
alphagov.github.io/a11y-dev-workshop/exercise4
Go to:
alphagov.github.io/a11y-dev-workshop/exercise5
A single interactive component that lets a user show or hide content. Typically it is closed (collapsed) by default.
"As an Assistive Technology (AT) user I want to know when additional content is available, how to access that content, and to know whether the content is currently shown or not"
The disclosure component must:
Write accessibility acceptance criteria relating to focus
The disclosure control must:
Write accessibility acceptance criteria relating to interaction
The disclosure control must:
Write accessibility acceptance criteria relating to appearance
The disclosure control must:
Write accessibility acceptance criteria relating to state
The disclosure control must:
Go to:
alphagov.github.io/a11y-dev-workshop/exercise6
The disclosure control does not:
The disclosure control does not:
Things mentioned during the workshop:
github.com/alphagov/a11y-dev-workshop/bllob/gh-pages/references.md