You're only supposed to blow the bloody doors off!

You're only supposed to blow the bloody doors off!

W3C Developer meetup, San Francisco November 2017

LĂ©onie Watson ~ The Paciello Group (TPG)

5... 4... 3... 2... 1...

Screen readers

Software that translates on-screen content into synthetic speech

Jaws NVDA Voiceover Narrator

Screen reader demo: text

Screen reader demo: headings

Web controls

<label for="this">Bold</label>
< type="checkbox" id="this" checked>
Role
checkbox
Name
Bold
State
Focusable, Focused, Checked

DOM tree

DOM information for an HTML checkbox

Accessibility tree

Accessibility tree information for an HTML
checkbox

Accessibility APIs

Windows
UI Automation (UIA)
MS Active Accessibility (MSAA)
IAccessible2 (IA2)
Mac OS
OSX Accessibility Protocol (AXAPI)
Linux
Accessibility Toolkit (ATK)
AT Service Provider Interface (AT-SPI)

Accessibility mappings

Define how role, state, properties, and keyboard focus for native elements are handled in the browser

Polyfill missing semantics

When native accessibility information is unavailable

Don't use ARIA

Use native HTML whenever possible

Native HTML

<button>Tequila!</button>

var button = document.getElementById('button');
button.addEventListener('click', doSomething, false);

Polyfilled HTML

<span id="button" role="button" tabindex="0">Tequila!</span>

var button = document.getElementById('button');
button.addEventListener('click', doSomething, false);

button.addEventListener('keydown', function(event) {
    if (event.keyCode == 13 || event.keyCode == 32) {
        doSomething();
    }
});

Screen reader demo: button

Don't break native semantics

<button role="heading" aria-level="1">Tequila!</button>

Screen reader demo: broken semantics

Make it work with a keyboard

When you create custom components it's your responsibility to make it work with the keyboard

Supplement existing interaction

<a href="#here" id="button" role="button">Tequila!</a>

var button = document.getElementById('button');
button.addEventListener('keydown', function(event) {
    if (event.keyCode == 13) {
        doSomething();
    }
});

Provide all interaction

<span id="button" role="button" tabindex="0">Tequila!</span>

var button = document.getElementById('button');
button.addEventListener('keydown', function(event) {
    if (event.keyCode == 13 || event.keyCode == 32) {
        doSomething();
    }
});

Screen reader demo: provide all interaction

Don't trigger applications mode

<body role="application">...</body>

Stops screen reader commands from working and hands navigation over to the webapp

Roles that trigger applications mode

Many ARIA roles trigger applications mode automatically, including:

Screen reader demo: application mode with tablist

Keyboard focus: roving tabindex

Keyboard interaction: event listeners

Listen for keydown and capture keycodes:

Screen reader demo: application mode with tablist and keyboard interaction

Manipulate the accessibility tree carefully

Accessibility Object Model (AOM): experimental JavaScript API that enables developers to modify the accessibility tree

Chrome Safari Firefox

AOM phases

  1. Modify the semantic properties of the accessibility node associated with a DOM node;
  2. Directly respond to events or actions from AT;
  3. Create virtual accessibility nodes (not associated with DOM nodes);
  4. Programmatically explore the accessibility tree, and access the computed properties of accessibility nodes.

AOM Phase 1

Has landed in Chrome Canary behind the flag:

--enable-blink-features=AccessibilityObjectModel

HTML code

<span id="button">Tequila!</span>
<div id="container">
Makes me happy!
</div>

Create DOM node references

var button = document.getElementById('button');
var container = document.getElementById('container');

Modify DOM node properties

button.setAttribute('tabindex', 0);
container.setAttribute('hidden', true);

Modify accessible node properties

button.accessibleNode.role = "button";
button.accessibleNode.expanded = false;

Create AccessibleNodeList

var content = new AccessibleNodeList();
content.add(container.accessibleNode);

Create the function

    function disclose(event) {
        if(container.getAttribute('hidden')) {
            button.accessibleNode.expanded = true;
            button.accessibleNode.controls = content;
            container.removeAttribute('hidden');
        }
        else {
            button.accessibleNode.expanded = false;
            button.accessibleNode.controls = null;
            container.setAttribute('hidden', true);
        }
    }

Add event listeners

    button.addEventListener('click', disclose, false);
    button.addEventListener('keydown', function(event) {
        if (event.keyCode == 13 || event.keyCode ==32) {
            disclose();
        }
    });

Screen reader demo: AOM disclosure

You're only supposed to blow the bloody doors off!

Thank you