Accessible JavaScript

Created by Marcy Sutton / @marcysutton
Senior Front-End Engineer, Deque Systems

Who is Marcy Sutton?

axe-core Web-A11y Slack
AngularJS Girl Develop It

The old days

  • Flash and keyboard navigation
  • Screen readers and JavaScript
  • Page reloads for data interactions
  • Car phones in Miatas

The Web has evolved. Yay!
How do we code for accessibility now?

What is accessibility?

W3.org

The Web is fundamentally designed to work for all people, whatever their hardware, software, language, culture, location, or physical or mental ability.

Who are we talking about?

  • Blind & Low Vision
  • Color-Blind
  • Deaf & Hard of Hearing
  • Impaired Mobility
  • Cognitive/Learning
  • AND EVERYONE ELSE

A holistic approach to accessibility
makes the web better for everyone

Disabilities as permament or situational

Web pages are more than
just visible

  • Semantic HTML markup
  • Headings
  • Landmark roles
  • Form labels
  • Image alt text
  • Visually hidden text

Demos

Web content is more than
just audible

  • Video/audio captions
  • Transcripts
  • Audio descriptions
  • User interactions

Low contrast
impacts people more than you think

http://webaim.org/articles/visual/lowvision

Low contrast footer
Low contrast footer with simulated vision impairment

But you came to hear about
Accessibility & JavaScript

JavaScript Framework Hotness

Let’s talk about:

  • Keyboard events
  • Icon buttons
  • Focus management
  • Testing tools

Creating accessible actions

Empty buttons and links: bad!

  <a ng-href="#/wrong-trousers"></a>

  <button ng-click="start()">
    <i class="icon"></i>
  </button>
			            
Unique and purposeful link text: good!

  <a ng-href="#/wrong-trousers">Techno-Trousers</a>

  <button ng-click="start()" aria-label="Start Day">
      <i class="icon"></i>
  </button>
		              

Creating accessible actions Continued

Empty buttons and links: bad!

  <a ng-href="#/wrong-trousers"></a>

  <button ng-click="start()">
    <i class="icon"></i>
  </button>
			            
Unique and purposeful link text: good!

  <a ng-href="#/wrong-trousers">Techno-Trousers</a>

  <button ng-click="start()">
      <i class="icon" aria-hidden="true"></i>
      <span class="icon-text">Start Day</span>
  </button>
		              

Button Demo

“Hidden” vs. “Offscreen” Styles


  [hidden] {
    display: none;
    visibility: hidden;
  }






	  				  
CSS

  .visuallyhidden {
    border: 0; 
    clip: rect(0 0 0 0); 
    height: 1px; 
    margin: -1px; 
    overflow: hidden; 
    padding: 0; 
    position: absolute; 
    width: 1px;
  }
	  				  
CSS

WebAIM on invisible content

Keyboard navigation

Any element can receive focus with tabindex="0".


   <div tabindex="0" class="nav-right"
   	role="button" aria-label="Next Slide">
   </div>
  					
HTML

  $('.nav-right').on('click keydown', (event) => {
      if (event.type === 'click' || event.keyCode === 13) {
          navRightClicked();
      }
  });
					  
jQuery

Use native
buttons and links first.

They come with native ARIA semantics as well as keyboard support.

Skip Links

Skip Links

Useful for everyone. Make them visible on focus:

 
  li.skip-link {
    display: block;
    margin: 0;
    padding: 0;
    position: absolute;

    a {
      display: block;
      position: absolute;
      left: -10000px;
      top: 0;
      width: 200px;
    
      &:focus {
        left: 0;
      }
    }
  }
  [tabindex="-1"]:focus {
    outline: none;
  }

  					
SCSS

  <ul>
    <li>
      <a href="#main">
        Skip to Main content
      </a>
    </li>
  </ul>

  <main id="main" tabindex="-1">

  </main>
						
HTML
http://codepen.io/marcysutton/pen/PZgbmm

Mega Menus

Mega Menus (fixed)

  • Really hide inactive content
  • Make top level links into toggles
  • Close with escape key

Focus Management

Ensure focus is not dropped

Important for:

  • Client-side rendering
  • Deleting items in a UI
  • Interactive widgets

Focus management: a strategy


 App.FocusManager = class FocusManager {
   constructor() {
     $('body').on('focusin', e => {
       return this.oldFocus = $(e.target);
     });

     App.bind('rendered', e => {
       if (!this.oldFocus) { return; }
       if (this.oldFocus.data('focus-id')) { return this._focusById(); }
     });
   }

   _focusById() {
     let focusId = this.oldFocus.data('focus-id');
     let newFocus = document.querySelector(`#${focusId}`);
     if (newFocus) { return MyApp.focus(newFocus); }
   }
 };
					  
JavaScript

Focus Management

Which item has focus? (debugging utility)


  $('body').on('focusin', function() { 
    console.log(document.activeElement); 
  });
					  
JavaScript (jQuery)

Testing for Accessibility

We can achieve digital equality by making accessibility part of our web development workflow.

Paul Adam's Bookmarklets

http://pauljadam.com/bookmarklets/

Paul's Bookmarklets page

aXe-core
Open Source Accessibility Engine

  • Browser extensions
  • Unit test integration
  • Selenium Webdriver integration

aXe Chrome extension

aXe Chrome extension

Unit Test Integration


  npm install axe-core
							

  describe('Form component', function () {
    document.getElementsByTagName('body')[0].insertAdjacentHTML('beforeend',
      '
' + '' + '' + '
'); it('should have no accessibility errors', function (done) { var n = document.getElementById('username'); axe.a11yCheck(n, null, function (result) { expect(result.violations.length).toBe(0); done(); }); });

https://github.com/marcysutton/axe-jasmine-unit

Webdriver Integration


  npm install axe-webdriverjs
							

  var selenium = require('selenium-webdriver'),
      AxeBuilder = require('axe-webdriverjs');

      describe('Selenium-aXe Tutorial', function() {
        beforeEach(function(done) {
          this.driver = new selenium.Builder()
            .forBrowser('firefox').build();
          this.driver
            .get('http://localhost:8000')
            .then(function() { done(); });
        });
        afterEach(function() {
          this.driver.quit();
        });
        it('Should have no accessibility violations', function(done) {
          AxeBuilder(this.driver)
            .analyze(function(results) {
              expect(results.violations.length).toBe(0);
              done();
            })
        });
      });
							

https://github.com/marcysutton/axe-webdriverjs-demo

Learn more on Github

https://github.com/dequelabs

Deque Labs on Github

Should your mobile site
be accessible?

It’s About User Experience.

We can make it better.

Resources

Questions?

Twitter: @marcysutton

Github: @marcysutton