PayPal's open source approach to accessibility


Nawaz @PayPalInclusive

Accessibility world needs open source and vice versa

  • People with Disability constantly lookout for better software to access outer world
  • More inaccessible libraries with growth of Opensource (NodeJS, gitHub etc.)

    More info : Article on why open source needs Accessibility standards
  • Currently there are a very small number of like minded people who contribute. BUT We Need more...

Innovate-Adapt-Evolve

A walk-through of our Innovation Journey:

  1. SkipTo Plug-in
  2. Bootstrap Plug-in
  3. amCharts Plug-in
  4. Accessible HTML5 Video Player
  5. AATT (Automated Accessibility Testing Tool)

Skip Navigation Links

  • Are a way to Bypass Blocks of (repeated) content (WCAG 2.4)
  • Without using this link
    • Keyboard user needs to tab through approximately 40 links to reach the main story
    • Screen reader user have to listen to 200 words
    • Screen magnifier user must search around for the location of the main body

Classical Skipto

Classical image of skip to main content on webAim website

It has been their for a quiet long time...........

SkipTo Plugin

https://github.com/paypal/skipto
  • Replacement for your old classic “Skip to main content” link
  • Scans the full page for
    • Heading (e.g h1, h2, h3 and h4 elements)
    • ARIA landmarks (e.g. banner, navigation, main and search)
    • HTML5 Section Elements (e.g. main, section[aria-label], section[aria-labelledby]
    • Any element with the id specified via the configuration file.
    • Any element with the custom class specified via the configuration file.
  • Displays as a nice Menu Button
  • Screen Readers announce it as “SkipTo menu Collapsed”

SkipTo Plugin

Screen Shot of SkipTo in expanded state

SkipTo Plugin - How to implement

Just add the JavaScript plugin to your HTML file


						
					

SkipTo Plugin - How to Configure

					

				

Also available as Wordpress and Drupal plugins

Bootstrap Plugin

https://github.com/paypal/bootstrap-accessibility-plugin

Pros

  • Makes many of the components of Bootstrap library accessible for keyboard and screen reader users
  • Experiment with Bootstrap without having to modify the original code
  • Independent of Bootstrap's release timeliness
  • Avoid other people having to hack Bootstrap code if they just want to get accessibility features

Cons

  • Another JavaScript file and CSS files need to be loaded on the page (but wait! you can Lazy Load)

Bootstrap Plugin - How to implement

GITHUB Repo : https://github.com/paypal/bootstrap-accessibility-plugin/

Demo : http://paypal.github.io/bootstrap-accessibility-plugin/demo.html

Bootstrap 3.3.5 is lot more accessible. Thanks to Patrick H. Lauke

P.S.

  • Bootstrap is just an famous example we picked up
  • There are lot more open source projects in the wild wild web which are used in many websites and making those sites even more inaccessible
  • SOS

amCharts Plugin

https://github.com/paypal/amcharts-accessibility-plugin
  • Example for making Interactive charts accessible
  • SVG Accessibility

Classical Chart Accessiblty

Problems with usual ways

  • Data is duplicated as in a hidden table
  • Too much text to describe the chart
  • Only Basic textual information available to Screen reader users
  • Lot of maintenance

amCharts accessibility Plugin (Interactivity)

For keyboard users

  • Can navigate with Left and Right arrow keys
  • Cursor tooltip is shown when the arrow keys are pressed
  • Tab key to navigate within chart, left and right sliders
  • Applies aria-label, aria-valuemin, aria-valuemax, aria-valuetext and aria-valuenow for left and right sliders

amCharts accessibility Plugin

For Screen Readers

  • Applies role of Application to the chart
  • Creates a hidden status Div to announce the Tooltips displayed
  • Announces the slider and the value selected using slider

amCharts accessibility Plugin - How to implement




					

Play with Demo

amCharts accessibility Plugin - Demo

Accessible HTML5 Video Player

https://github.com/paypal/accessible-html5-video-player
  • Supports VTT caption file
  • Uses native HTML5 form controls for volume (range input) and progress indication (progress element).
  • Accessible to keyboard-only users and screen reader users.
  • Option to set captions on or off
  • Option to set number of seconds to rewind and forward.
  • width adjusts to width of video element.
  • Written in "vanilla" JavaScript.

Accessible HTML5 Video Player

Screenshot of HTML5 player

Demo

Automated Accessibility Testing Tool (AATT)

https://github.com/paypal/AATT

To find out Frequent Accessibility Errors

  • Missing alt attributes for images
  • Missing explicit relationships between form fields and their labels
  • Tables without headers or without explicit relationships between header cells and data cells
  • Use of deprecated, presentational elements and attributes
  • Events bound to items that are not discoverable via keyboard
  • Poor color contrast
  • Blank link text

AATT - Why?

  • Plenty of tools for free tool testing
  • Mostly in form of Browser toolbars - Test page by page
  • API outside of company and would not suit our requirements

AATT - What?

  • A tool within Corporate network to test page by page
  • Serves an API which accepts html "source" and returns back errors
  • Integrates easily with our existing testing framework, we did it with Java, NodeJS testing suite
  • Made of NodeJS + Phantom JS (headless WebKit browser) + Selenium Webdriver

AATT - Overview

Low Level Diagram of Accessibility Testing Tool

AATT - Options

  • "source" to send the HTML source of the page. Can be a whole page or partial page source
  • "priority" to fetch results based on issue priorities like P1, P2, P3 or P4.
  • "engine" htmlcs, chrome, axe ( Can add more)

AAT- SNIFF URL

				
	app.post('/sniffURL', function(req, res) {
 		var childArgs
 		, userName = ''
 		, d = new Date()
        , customDateString = d.getHours() +'_'  + d.getMinutes() + '_' + d.getSeconds() +'_'+ d.getMonth() + '_' + d.getDate() + '_' + d.getFullYear()
        , dirName = "screenshots/" + customDateString
        , scrshot = req.body.scrshot
        , msgErr = req.body.msgErr
        , msgWarn = req.body.msgWarn
        , msgNotice = req.body.msgNotice
    	, eLevel=[]

    	if(typeof msgErr !== 'undefined' && msgErr=='true') eLevel.push(1);
    	if(typeof msgWarn !== 'undefined' && msgWarn=='true') eLevel.push(2);
    	if(typeof msgNotice !== 'undefined' && msgNotice=='true') eLevel.push(3);

    	//Default to Error
		if(typeof msgErr === 'undefined' &&  typeof msgWarn === 'undefined' && typeof msgNotice === 'undefined') eLevel.push(1);

		fs.mkdirSync(dirName);		//Create SCREEN SHOT DIRECTORY
		if (typeof req.session.userName !== 'undefined') {
			userName = req.session.userName;
			log('Testing logged in session: -> ', userName)
		}
		childArgs = ['--config=config/config.json', path.join(__dirname, 'src/PAET.js')
						, req.body.textURL
						, 'WCAG2AA'
						, userName
						, dirName
						, scrshot
						, eLevel
					];
		childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
			res.json({ userName: userName, data: stdout });
			log(stdout);
		});
	});

AAT- API

				
	app.post('/evaluate', function(req, res) {
		var tempFilename = 'tmp/'+ new Date().getTime() + '.html';

		var priority = req.body.priority;	// Piority Eg P1,P2,P3,P4  	default:all
		var output = req.body.output;		// Eg. json, string  		default: string
		var engine	= req.body.engine;		//Eg htmlcs, chrome 		default:htmlcs

		if(typeof priority === 'undefined' || priority ==='') priority = 'P1,P2,P3,P4';
		if(typeof output === 'undefined' || output ==='') output = 'string';
		var childArgs = ['--config=config/config.json', path.join(__dirname, 'src/HTMLCS_Run.js'), tempFilename, 'WCAG2AA', priority, output];

		switch(engine){
			case "chrome":
				var childArgs = ['--config=config/config.json', path.join(__dirname, 'src/chrome.js'), tempFilename, output];
				break;
			case "axe":
				var childArgs = ['--config=config/config.json', path.join(__dirname, 'src/axe.js'), tempFilename, output];
				break;
		}		
		fs.writeFile(tempFilename, req.body.source, function (err,data) {
		  if (err) {
		    return error(err);
			res.end();
		  }
		 	childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
			 	stdout = stdout.replace('done','');
		    	res.writeHead(200, { 'Content-Type': 'text/plain', "Access-Control-Allow-Origin":"*" });
		    	res.write(stdout);
		    	res.end();
		    	log(stdout);
				fs.unlink(tempFilename);			  
			});
		});
	});	 	

AATT - Demo

Contact

PayPal Accessibility

Follow us on Twitter / @PayPalInclusive