Accessibility: A Journey to Accessible Rich Components

Preview:

Citation preview

A Journey to Accessible Rich UI Components

with Jason Jang

“Journey” sounds inappropriately epic and kind of cornered me into a theme, for this, my first talk.

What to Expect▹My story▹Important Considerations for our

organization▹Code Examples of making a Rich UI

Component accessible

Sometimes the hardest part of learning a language, is learning the language around

the language.

Disclaimer

Whoa, deep.

Some Terminology▹a11y > accessibility▹component > a part of an interface▹Rich UI > interactive components

Whoa, deep.

My Story

Whoa, deep.

In the beginning...▹“Making websites” was a hobby▹… that became a side gig▹… that became a part-time gig▹… that became a full-time gig at an agency▹… that became a stint as a freelancer▹… that became a full-time gig at Achievers

There. There’s your journey.

First Encounter with a11y▹Everyone uses the Internet▹People use screen readers? Never got use one.▹A11y considered a checkmark▹All text and images

First Encounter with a11ySemantic HTML and good markup

▹ Headings, Lists, Links▹ <b> <i> vs <strong> <em>

Landmark Roles: ▹ <div role=”banner”>▹ <div role=”form”>▹ <div role=”main”>▹ <div role=”navigation”>▹ <div role=”search”>

a11y Tools▹WAVE Accessibility Tool▹aChecker▹Quail (JS Accessibility Tool)▹Google Accessibility Tool

Fast-forward 5 or so yearsI lost count

Platform Demo

Jason, can we make this accessible?

ARIA SAVES THE DAY!

WHY ARIA?...and not Arya?

WAI-ARIA!Web Accessibility Initiative – Accessible Rich Internet Applications

Henceforth referred to as accessibility API or ARIA

listitemlogmainmarqueemathmenumenubarmenuitemmenuitemcheckboxmenuitemradionavigationnoteoptionpresentation

dialogdirectorydocumentformgridtablegridcellgroupheadingimginput (abstract role)landmark linklistlistbox

alertalertdialogapplicationarticlebannerbuttoncheckboxcolumnheadercomboboxcommandcomplementarycompositecontentinfodefinition

progressbarradioradiogrouprange (abstract role)regionroletype (abstract role)rowrowgrouprowheaderscrollbarsearchsection (abstract role)

LOOK AT ALL THESE ROLES!

alertalertdialogapplicationarticlebannerbuttoncheckboxcolumnheadercomboboxcommandcomplementarycompositecontentinfodefinitiondialogdirectorydocumentformgridtablegridcellgroupheadingimginput (abstract role)landmark linklistlistbox

listitemlogmainmarqueemathmenumenubarmenuitemmenuitemcheckboxmenuitemradionavigationnoteoptionpresentation

listitemlogmainmarqueemathmenumenubarmenuitemmenuitemcheckboxmenuitemradionavigationnoteoptionpresentation

dialogdirectorydocumentformgridtablegridcellgroupheadingimginput (abstract role)landmark linklistlistbox

progressbarradioradiogrouprange (abstract role)regionroletype (abstract role)rowrowgrouprowheaderscrollbarsearchsection (abstract role)

LOOK AT ALL THESE ROLES!

a11y: You’ve Changed

This is not the Aria you were looking for, and that’s a reference to something else entirely.

a11y: You’ve Changed▹ Support for Rich Interfaces

▹new roles <div role=”button”>

▹presentation changes <div role=”button” aria-pressed=”true”>

▹asynchronous content <div role=”button” aria-pressed=”true”>

▹ a11y evaluation tools still useful elsewhere

We’re all equipped and ready to go!Right?

WaitBefore we could dig into it...

Important ConsiderationsFor your Organization

There were several

Important Considerations

1. Define Usersa. Assistive Technologies

2. Take Stock of Codebase and UI

3. Determine rollout plan

4. How will you influence a Paradigm Shift?

1. Define Users

1. Define Users▹Vision-impaired▹Dexterity-impaired▹Hearing impaired

1a. Assistive TechnologiesLearn about the Tools▹JAWS, NVDA, VoiceOver▹Windows Eyes, ZoomText▹Specialized Input Devices

2. Take Stock of YourCodebase and UI

2. Take Stock of Codebase and UI▹How is your markup?▹Identify and address Anti-Patterns▹Breakdown features into components so

you can tackle them individually (Agile)

3. Take Stock of Codebase and UI

3. Determine Rollout Plan

▹ Prioritize core features▹ Break down into components▹ Tackle global elements

▹ Don’t omit features or content

4. Influence a Paradigm Shift

▹a11y is NOT a checkmark▹Affects everyone in the development lifecycle

4. Influence a Paradigm Shift

Education▹ Devs and Testers need software training▹ Designers need to understand a11y needs for both

users and developers▹ Project Managers need to know how to break the

work down

4. Influence a Paradigm Shift

4. Influence a Paradigm ShiftProcess Improvement▹ Design mocks need to be vetted for a11y at design

stage before development begins▹ Pattern/Component Library even more valuable

4. Influence a Paradigm ShiftTesting▹ a11y testing can be expensive▹ Some automation possible▹ Manual testing required▹ Testing with real users is the only real test

Okay, with all things considered...

Accessible Rich UI Components

The Code Demo

a11y Rich UI Components...1. ...use WAI-ARIA for communicating:

▹ Roles▹ Presentation changes like state and visibility▹ Asynchronous content changes

2. …are fully keyboard accessible

Time for a quick

SCREEN READER DEMO

and now for some

CODE EXAMPLES

Code Examples1. Form Basics2. Live Regions3. Slider Example4. Tabs and Tab Panels

Code Example 1: Form Basics (1 of 3)

Code Example 1: Form Basics (2 of 3)

<label>Your email</label>

<input type="email" />

<label>Reason for contacting</label>

<select>

<option value="Option 1">Questions</option>

<option value="Option 2">Admiration</option>

<option value="Option 3">Can I get your number?</option>

</select>

<label>Message</label>

<textarea></textarea>

Code Example 1: Form Basics (3 of 3)

<label for="email">Your email</label>

<input id="email" type="email" />

<label for="reason">Reason for contacting</label>

<select id="reason">

<option value="Option 1">Questions</option>

<option value="Option 2">Admiration</option>

<option value="Option 3">Can I get your number?</option>

</select>

<label for="message">Message</label>

<textarea id="message"></textarea>

Code Example 2: Live Region (1 of 3)

<!-- FORM--><label for="message">Message</label><textarea id="message"></textarea><input class="button-primary" type="submit" value="Submit">

<!-- THROBBER TO INDICATE AJAX CALL --><img src="img/ajax-loader.gif" js-throbber class="hidden">

<!-- FEEDBACK FOR AJAX CALL --><div class="alert error hidden" js-ajax-alert="error" ><a href="#message">There was an error with your message</a></div>

<!-- LIVE REGION --><div role="alert" aria-live="assertive" aria-relevant="additions" class="a11yHiddenText" js-globalLiveRegion></div>

Code Example 2: Live Region (2 of 3)

<script> function formSubmit() { $("form").submit(function() { showThrobber(); $.ajax( "formSubmit.php" ) .done(function() { hideThrobber(); alert( "success" ); }) .fail(function() { hideThrobber(); alert( "error" ); }); }); }</script>

Code Example 2: Live Region (2 of 3)

Code Example 2: Live Region (3 of 3)

<script> function formSubmit() { $("form").submit(function() { showThrobber(); $.ajax( "formSubmit.php" ) .done(function() { hideThrobber(); updateLiveRegion("Form submitted successfully"); }) .fail(function() { hideThrobber(); updateLiveRegion("Form submit unsuccessful"); }); }); } function updateLiveRegion(text) { $("[js-globalLiveRegion]").html(text); }</script>

Code Example 2: Live Region (3 of 3)<script> function formSubmit() { $("form").submit(function() { submitPending(true); $.ajax( "formSubmit.php" ) .done(function() { submitPending(false); updateLiveRegion("Form submitted successfully"); }) .fail(function() { submitPending(false); updateLiveRegion("Form submit unsuccessful"); }); }); } function updateLiveRegion(text) { $("[js-globalLiveRegion]").html(text); } function submitPending(true) { showThrobber(true); disableSubmit(true); } function disableSubmit(state) { $("#submit") .attr("aria-disabled", state) .attr("disabled", "disabled") .addClass('.disabled'); }</script>

<div js-slider> <span class="ui-slider-handle" tabindex="0"></span></div>

Code Example 3: Slider

<div js-slider> <span class="ui-slider-handle" tabindex="0"

role="slider" aria-valuemin="0" aria-valuemax="500" aria-valuenow="0" aria-valuetext="0"></span></div>

$slider.slider({ value: 0, min: 0, max: 500, step: 50, slide: function(event, ui) { $display.html(ui.value); var $handle = $slider.find(".ui-slider-handle");

$handle .attr("aria-valuemin", 0) .attr("aria-valuemax", 500) .attr("aria-valuenow", 0) .attr("aria-valuetext", 0); }});

Code Example 4: Tabs

Code Example 4: Tabs<div id="tabs-container" js-tabContainer class="clearfix"> <ul class="tabs-menu"> <li class="current"><a href="#tab-1" js-tab>Tab 1</a></li> <li><a href="#tab-2" js-tab>Tab 2</a></li> <li><a href="#tab-3" js-tab>Tab 3</a></li> <li><a href="#tab-4" js-tab>Tab 4</a></li> </ul> <div class="tab"> <div id="tab-1" class="tab-content"> <p>...</p> </div> <div id="tab-2" class="tab-content"> <p>...</p> </div> <div id="tab-3" class="tab-content"> <p>...</p> </div> <div id="tab-4" class="tab-content"> <p>...</p> </div> </div></div>

Code Example 4: Tabs<div id="tabs-container" js-tabContainer class="clearfix"> <ul class="tabs-menu" role="tablist"> <li role="tab" aria-selected="true" class="current"><a href="#tab-1" js-tab>Tab 1</a></li> <li role="tab" aria-selected="false"><a href="#tab-2" js-tab>Tab 2</a></li> <li role="tab" aria-selected="false"><a href="#tab-3" js-tab>Tab 3</a></li> <li role="tab" aria-selected="false"><a href="#tab-4" js-tab>Tab 4</a></li> </ul> <div class="tab"> <div id="tab-1" class="tab-content" role="tabpanel" aria-hidden="false"> <p>...</p> </div> <div id="tab-2" class="tab-content" role="tabpanel" aria-hidden="true"> <p>...</p> </div> <div id="tab-3" class="tab-content" role="tabpanel" aria-hidden="true"> <p>...</p> </div> <div id="tab-4" class="tab-content" role="tabpanel" aria-hidden="true"> <p>...</p> </div> </div></div>

Code Example 4: Tabsfunction initTabsKeyboardA11y($tabsContainer) { $("[js-tabContainer]").keydown(function(e) { e.preventDefault();

var $currentTab = $(this).find("[role=tab].current [js-tab]"); var keyPressed = getKeyName(e.keyCode);

if (keyPressed === "right") { var $next = $currentTab.parent().next().find("[js-tab]") if ($next) { $next.trigger("click").focus(); } } else if (keyPressed === "left") { var $prev = $currentTab.parent().prev().find("[js-tab]") if ($prev) { $prev.trigger("click").focus(); } } });}

Knowledge Nugget!If you can’t find an ARIA ROLE that addresses your design pattern, there’s a good chance you have an ANTI-PATTERN (or they just call it by a different name :)

Time for another quick

SCREEN READER DEMOThis time on an accessible page

Keyboard Accessibility

Keyboard Accessibility▹ Screen Readers Provide shortcuts to traverse page▹ TAB is also commonly used▹ Certain ROLEs expect the use of arrow keys▹ You can often refer to OS or other online examples

for keyboard flow

Keyboard Accessibility● Get to know tabindex● Both ENTER and SPACEBAR should trigger

a click● In Forms, SPACEBAR activates, ENTER

submits the form

Biggest Hurdles▹Learning to use screen readers (ongoing!)▹Deciding where to start▹Testing

Added Benefits from A11yImproved UI▹Forces you to scrutinize UI decisions▹Opportunity to fix design decisions

Food for Thought▹ Decouple your a11y JS from regular JS▹ Create helpers for JS and SCSS▹ Here’s a clever way to enforce a11y

Before we finish...

Let’s Remember

Influence a Paradigm Shift▹A11y affects everyone▹Consider users, testers, designers, developers….

Let’s Also Remember

Rich Components...▹ Leverage WAI-ARIA to comm. with screen readers▹Provide Keyboard a11y

Special Thanks

Chris Gurney (PM) & Avinder Walia (Dev)

Recommended