Inclusion in Modern JS frameworks


Inclusive logo

Nawaz @mpnkhan

Web Accessibility

“People with disabilities can perceive, understand, navigate, and interact with the Web, and that they can contribute to the Web.”
https://www.w3.org/WAI/intro/accessibility.php

Statistics

More than 1 billion persons (15%) in the world have some form of disability.

WRD Report

'N' number of Senior Users

Old age people using computer

'N' number of Temporary Impairments

A User with Injured Hand using computer with single hand

'N' number of Situational Disabilities

Browsing Mobile in Sunlight

Design and develop for ‘future you’

Microsoft Inclusive Toolkit

Understanding Interactions of PWD

  • Visual - Keyboard, Screen reader, Magnifier, Custom stylesheet, HCM
  • Auditory - Caption, Description
  • Motor - Headmouse, Mouth stick , Switch, Trackball mouse,Adaptive keyboard, Voice recognition software
  • Cognitive - Screen Readers

Modern JS Frameworks

New Frameworks like buying new Car

Modern JS Frameworks

New Frameworks like buying new Car

Good Parts

  • Quick to production
  • Files separated by Functionality rather than Technology , easy for Modularity
  • JavaScript common technology between backend and front end engineers, so we get many engineers as full stack developers
  • Ready made code available for most problems

Not Good Parts

  • People understand less about the copy pasted code
  • Plenty of Non standard open source plugins , most of them not accessible
  • Screens or parts of screens that change unexpectedly

InAccessible examples in Tutorials

Angular InAccessible components

InAccessible examples in Tutorials

Angular InAccessible components

InAccessible components

Angular InAccessible components

InAccessible components

React InAccessible components

We'll cover React and AngularJS

  1. Form Labelling
  2. Focus management
  3. Faking a button
  4. Menu component
  5. Announcing changes
  6. Testing

React

  • Virtual DOM, updates only the diff
  • Less framework sugar unlike angular
  • One way data flow
  • JSX with ES6 and expressions inside code
  • React developer tool on FF and chrome

React Labels

Any Guess what’s wrong with this form?


class LoginForm extends Component {
  render() {
    return (
      
) } } Source: https://blog.codeship.com/designing-user-interfaces-with-react/

React Labels

Correct way to do


class LoginForm extends Component {
  render() {
    return (
      
) } }

Screen reader friendly content


.sr-only {
	position: absolute;
	left: -999em;
}						
.sr-only { 
	position: absolute !important; 
	clip: rect(1px 1px 1px 1px); 	/* IE6, IE7 */
	clip: rect(1px,1px,1px,1px); 
}
					

Focus Management

  1. Do no set focus before a component is fully rendered
  2. Use the right react lifecycle hooks for setting focus

Set focus on component mount - Using refs


class Focusinput extends React.Component {
  componentDidMount(){
    this.nameInput.focus();
  }
  render() {
    return(
      
{ this.nameInput = input; }} defaultValue="will focus" />
); } } ReactDOM.render( <Focusinput/>, document.getElementById('root') );
http://mpnkhan.github.io/test/examples/react/input_focus_componentdidMount.html

Set focus via component state


componentDidMount() {
  this.timerID = setInterval(
    () => this.ajaxUpdate(),
    3000
  );          
}
ajaxUpdate() {
  const id = Math.floor((Math.random()*1000)+1);
  this.setState({ id: id }, () => {
    this.nameInput.focus();
  });
}

render() {
  return (
    
{ this.nameInput = input; }} type="text" value={this.state.value} onChange={this.handleChange}/>
); }
http://mpnkhan.github.io/test/examples/react/input_focus_state.html
http://mpnkhan.github.io/test/examples/react/axiofetch.html

Problems with Fake elements

Have you experienced bizarre behavior of a web site or application?
  • Click on a link or button and it doesn’t tell you what happened.
  • Unable to perform a critical task because of this problem?
  • App report content changes as they occur, such that you don't have to re-scan the page to hunt for updated content?

Fake Button


  class Fakebutton extends React.Component {
        constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
       }
       handleClick(e) {
        console.log(this.props.inputRef)
        alert('clicked');
      }       

      render() {
        return(
          
Buy Now!!!
); } } ReactDOM.render( <Fakebutton />, document.getElementById('root') );
Buy Now!!!

Fake Button


    class Fakebutton extends React.Component {
        constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.handleKeyDown = this.handleKeyDown.bind(this);
       }
       handleClick(e) {
        alert('clicked');
      }       
       handleKeyDown(e) {
        if(e.key=='Enter' || e.key==' ') alert('Enter/Space');
      }
      render() {
        return(
          
Buy Now!!!
); } }
http://mpnkhan.github.io/test/examples/react/Fakebutton.html

Accessible Drop down MenuComponent

Accessible Drop down MenuComponent


    class Menu extends React.Component {
      constructor(props) {
        super(props);
       this.handleKeyDown = this.handleKeyDown.bind(this);
      }
      
    handleKeyDown = event => {
      var menu = ReactDOM.findDOMNode(this);
      var items = menu.getElementsByTagName('li');
      var index = Array.prototype.indexOf.call(items, event.target);
      if (!~index)                                      index = 0
      
      switch (event.key) {
        case 'ArrowDown':
          index++;
          if (index == items.length) index = 0;
          items.item(index).focus();
          //console.log(items.item(index).children[0]);
          break;
        case 'ArrowUp':
          index--;
          if (index < 0) index = items.length - 1;
          items.item(index).focus();
          break;
        case 'Enter':
        case ' ':
          items.item(index).children[0].click();
          break;          
        case 'Escape':
          //console.log(this.props.toggle);
          this.props.toggle.state = {isToggleOn: false};
          const cont = menu.parentNode;
          cont.className = 'dropdown';
          const btn = cont.querySelector('[role=button]');
          btn.setAttribute('aria-expanded','false');
          btn.focus();
      }	             
    }      
      
      render() {
        return(
              
        );
      }
    }
    class Button extends React.Component{
       constructor(props) {
        super(props);
        this.state = {isToggleOn: false};
        this.handleClick = this.handleClick.bind(this);
       }
       handleClick(e) {
          this.setState(prevState => ({
            isToggleOn: !prevState.isToggleOn
          }    
       ));         
      }
      componentDidUpdate() {
          const element = ReactDOM.findDOMNode(this);
          element.querySelector('li').focus();      
        }      
      render() {
        return(
             
        );
      }         
    }

	var sports =[
			{'id':1, 'content':'Cricket','link':'http://sports.yahoo.com'}, 
			{'id':2, 'content':'Tennis','link':'http://www.bbc.com/sport'},
			{'id':3, 'content':'Badminton','link':'http://bwfbadminton.com/'}
			]
    ReactDOM.render(
      <Button key="1" items={sports}/>,
      document.getElementById('container')
    );	
http://mpnkhan.github.io/test/examples/react/menu.html

Announce Dynamic content

  • aria-live="off | polite | assertive"
  • aria-atomic="true | false" - read the entire region or only what has changed
  • aria-relevant =" additions | removals | text | all" -

<div aria-live="polite"  aria-atomic="true" aria-relevant="additions"> Ajax Updates</div>
					

Implicit live roles:


<div role="alert" id="errMsgId"> Important Error Message</div> 
					

Linting with eslint-plugin-jsx-a11y


$ eslint src webpack.config.babel.js --ext .js,.jsx 

/Users/pkhan/Desktop/Nawaz/Outside/learn/react/src/shared/component/button.jsx
  11:3  error  The element button has an implicit role of button. Defining this explicitly is redundant and should be avoided  jsx-a11y/no-redundant-roles

/Users/pkhan/Desktop/Nawaz/Outside/learn/react/src/shared/component/modal-example.jsx
   6:48  error  aria-modal: This attribute is an invalid ARIA attribute                                                         jsx-a11y/aria-props
  17:11  error  The element button has an implicit role of button. Defining this explicitly is redundant and should be avoided  jsx-a11y/no-redundant-roles

/Users/pkhan/Desktop/Nawaz/Outside/learn/react/src/shared/component/nav.jsx
  23:5  error  The element button has an implicit role of button. Defining this explicitly is redundant and should be avoided  jsx-a11y/no-redundant-roles

/Users/pkhan/Desktop/Nawaz/Outside/learn/react/src/shared/component/page/home.jsx
  26:13  error  The element button has an implicit role of button. Defining this explicitly is redundant and should be avoided  jsx-a11y/no-redundant-roles

✖ 5 problems (5 errors, 0 warnings)

error Command failed with exit code 1.
			

Linting

In .eslintrc.json


{
  "extends": [
    "plugin:jsx-a11y/recommended"
  ],
  "plugins": [
    "jsx-a11y"
  ],		
}  
			

In package.json

			
 "scripts": {
    "lint": "eslint src webpack.config.babel.js --ext .js,.jsx",
}
			
https://github.com/evcohen/eslint-plugin-jsx-a11y

Linting with react-a11y


$ npm install react-a11y				
			

In app.jsx file


import a11y from 'react-a11y'		//start
.
.
.
a11y(React)				//Last line
export default App


			

Linting with react-a11y

Shows error in console


$ yarn start
yarn start v0.22.0
$ yarn dev:start 
yarn dev:start v0.22.0
$ nodemon -e js,jsx --ignore lib --ignore dist --exec babel-node src/server 
Server running on port 8000 (development).
Keep "yarn dev:wds" running in an other terminal.
Nav You have an unlabeled element or control. Add `aria-label` or `aria-labelledby` attribute, or put some text in the element.
Nav You have an unlabeled element or control. Add `aria-label` or `aria-labelledby` attribute, or put some text in the element.				
			
https://github.com/reactjs/react-a11y

Angular JS from google

Labelling

Label Form elements in templates


 template: `
 	
`,

Labelling

Dynamic elements should also be labelled


 template: `
      
`,

Focusable and keyboard accessible


  • {{hero.id}} {{hero.name}}
onKeydown(event: any): void{ if(event.key=='Enter'){ event.target.click(); } }
or

Focusable and keyboard accessible


<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
	#item    
(keydown.enter)="item.click()">
 			

For Angular1 components use ngAria


$yarn add angular-aria@X.Y.Z
(function(angular) {
  'use strict';
angular.
  module('ngAria_ngModelExample', ['ngAria']);
 			

For Angular1 components use ngAria


  
    Custom checkbox
  
adds Aria attributes
  
    Custom checkbox
  
   		

NgAria only helps certain use cases



Angular1 Accessibility docs

Angular Material Design

Angular Material Design components are better https://material.angular.io/components

Summary

  1. Write meaningful HTML
  2. Use ARIA attributes refer to W3C,MDN for Aria usage
  3. Manage focus
  4. Make your app keyboard accessible
  5. Alert user for content change

Resources

Questions, Thank you.