On Github marcysutton / angular-a11y
Marcy Sutton, Seattle, USAAccessibility Engineer, Angular Core Team Member
Legend: waffle denotes a major topic in client-rendered app accessibility
<md-checkbox tabindex="0" ...
<md-checkbox tabindex="0" ng-keypress="doStuff()" ...
Button
// should be: Button
<md-checkbox tabindex="0" role="checkbox" aria-checked="true"> Checkbox </md-checkbox>Roles, states and properties
Menu
Waffles!
<md-radio-group ng-model="data.group3"> <md-radio-button ng-repeat="it in avatarData" ng-value="it.value"> <md-icon md-svg-icon="{{it.id}}"></md-icon> </md-radio-button> </md-radio-group>
aria-label is missing.
<md-radio-group ng-model="data.group3"> <md-radio-button ng-repeat="it in avatarData" ng-value="it.value" aria-label="{{it.title}}"> <md-icon md-svg-icon="{{it.id}}"></md-icon> </md-radio-button> </md-radio-group>
Boom! Labeled radio buttons.
<md-sidenav class="md-sidenav-right" md-component-id="right"> <md-content ng-controller="RightCtrl"> <form> <md-input-container> <label for="testInput">Test input</label> <input type="text" id="testInput" ng-model="data" md-sidenav-focus> </md-input-container> </form> <md-button ng-click="close()" class="md-primary"> Close </md-button> </md-content> </md-sidenav>Angular Material Sidenav with custom focus
<aria-status role="status" aria-live="assertive"> <p ng-repeat="message in messages">{{message}}</p> </aria-status>
switch (self.matches.length) { case 0: return 'There are no matches available.'; case 1: return 'There is 1 match available.'; default: return 'There are ' + self.matches.length + ' matches available.'; }Angular Material Autocomplete Source
angular.module('app', ['ngAria'], function($ariaProvider) { $ariaProvider.config({ ariaHidden: false ...
<body> <!-- page content here --> <script src="angular.min.js"></script> <script src="angular-aria.js"></script> </body>
<md-checkbox ng-disabled="true" aria-disabled="true"...
.directive('ngDisabled', ['$aria', function($aria) { return $aria.$$watchExpr('ngDisabled', 'aria-disabled'); }])ngAria Source for ngDisabled for ngDisabled opens in a new window
<div ng-click="ohNoYouDidnt()"></div>
.directive('ngClick',['$aria', function($aria) { return { compile: function(scope, elem, attr) { var nodeBlackList = ['BUTTON','A','INPUT','TEXTAREA','SELECT']; if (!isNodeOneOf(elem, nodeBlackList)) { if (!elem.attr('role') && config.buttonRole) { elem.attr('role', 'button'); } if (config.bindKeypress) { elem.on('keypress', function(event) { if (event.keyCode === 32 || event.keyCode === 13) { scope.$apply(callback); ...https://github.com/angular/angular.js/pull/10318 Opens in a new window
exports.config = { plugins: [{ tenonIO: { options: { // options.src will be added by the test }, printAll: false, }, chromeA11YDevTools: true, path: 'node_modules/protractor/plugins/accessiblity' }] }Plugin Documentation Link opens in a new window
<button ng-focus="anticipationEvent()" ng-click="deliverWaffles()" id="{{item.id}}"> Give me waffles </button>Angular 1: attributes
<button (focus)="anticipationEvent()" (click)="deliverWaffles()" [waffle-id]="item.id"> Give me waffles </button>Angular 2: properties
All links open in new windows
Accessible Angular.js@marcysutton / marcysutton.com/gotocon