Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit fc2bec2

Browse files
author
Marcy Sutton
committed
docs(ngAria): Add Usage Details and Examples
1 parent ffb14ae commit fc2bec2

File tree

3 files changed

+236
-48
lines changed

3 files changed

+236
-48
lines changed

docs/content/api/index.ngdoc

+21
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,27 @@ or JavaScript callbacks.
161161
</tr>
162162
</table>
163163

164+
## {@link ngAria ngAria}
165+
166+
Use ngAria to inject common accessibility attributes into directives and improve the experience for users with disabilities.
167+
168+
<div class="alert alert-info">Include the **angular-aria.js** file and set ngAria as a dependency for this to work in your application.</div>
169+
170+
<table class="definition-table spaced">
171+
<tr>
172+
<td>
173+
{@link ngAria#service Services}
174+
</td>
175+
<td>
176+
<p>
177+
The {@link ngAria.$aria $aria} service contains helper methods for applying ARIA attributes to HTML.
178+
<p>
179+
<p>
180+
{@link ngAria.$ariaProvider $ariaProvider} is used for configuring ARIA attributes.
181+
</p>
182+
</td>
183+
</tr>
184+
</table>
164185

165186
## {@link ngResource ngResource}
166187

docs/content/guide/accessibility.ngdoc

+133-26
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,23 @@ assistive technologies used by persons with disabilities.
1212

1313
##Including ngAria
1414

15-
Using ngAria is as simple as requiring the ngAria module in your application. ngAria hooks into
15+
Using {@link ngAria ngAria} is as simple as requiring the ngAria module in your application. ngAria hooks into
1616
standard AngularJS directives and quietly injects accessibility support into your application
1717
at runtime.
1818

1919
```js
2020
angular.module('myApp', ['ngAria'])...
2121
```
2222

23+
###Using ngAria
24+
Most of what ngAria does is only visible "under the hood". To see the module in action, once you've
25+
added it as a dependency, you can test a few things:
26+
* Using your favorite element inspector, look for ngAria attributes in your own code.
27+
* Test using your keyboard to ensure `tabindex` is used correctly.
28+
* Fire up a screen reader such as VoiceOver to listen for ARIA support.
29+
[Helpful screen reader tips.](http://webaim.org/articles/screenreader_testing/)
30+
31+
##Supported directives
2332
Currently, ngAria interfaces with the following directives:
2433

2534
* <a href="#ngmodel">ngModel</a>
@@ -31,7 +40,7 @@ Currently, ngAria interfaces with the following directives:
3140

3241
<h2 id="ngmodel">ngModel</h2>
3342

34-
Most of ngAria's heavy lifting happens in the [ngModel](https://docs.angularjs.org/api/ng/directive/ngModel)
43+
Most of ngAria's heavy lifting happens in the {@link ngModel ngModel}
3544
directive. For elements using ngModel, special attention is paid by ngAria if that element also
3645
has a a role or type of `checkbox`, `radio`, `range` or `textbox`.
3746

@@ -47,15 +56,41 @@ attributes (if they have not been explicitly specified by the developer):
4756

4857
###Example
4958

50-
```html
51-
<md-checkbox ng-model="val" required>
52-
```
53-
54-
Becomes:
55-
56-
```html
57-
<md-checkbox ng-model="val" required aria-required="true" tabIndex="0">
58-
```
59+
<example module="ngAria_ngModelExample" deps="angular-aria.js">
60+
<file name="index.html">
61+
<style>
62+
some-checkbox {
63+
background-color: black;
64+
color: white;
65+
}
66+
</style>
67+
<div print-markup>
68+
<form>
69+
<some-checkbox ng-model="user.subscribe" required>
70+
Fake Checkbox
71+
</some-checkbox>
72+
</form>
73+
</div>
74+
<script>
75+
var app = angular.module('ngAria_ngModelExample', ['ngAria']);
76+
77+
app.directive('printMarkup', function() {
78+
return {
79+
restrict: 'A',
80+
link: function($scope, $el, $attrs) {
81+
var el = $el[0].querySelector('form');
82+
var newEl = document.createElement('div');
83+
var output = 'Becomes: <pre><code>' +
84+
el.innerHTML.replace(/&/g, '&amp;').replace(/</g, '&lt;') +
85+
'</code></pre>';
86+
newEl.innerHTML = output;
87+
el.parentNode.insertBefore(newEl, el.nextSibling);
88+
}
89+
}
90+
});
91+
</script>
92+
</file>
93+
</example>
5994

6095
ngAria will also add `tabIndex`, ensuring custom elements with these roles will be reachable from
6196
the keyboard. It is still up to **you** as a developer to **ensure custom controls will be
@@ -106,6 +141,24 @@ screen reader users won't accidentally focus on "mystery elements". Managing tab
106141
child control can be complex and affect performance, so it’s best to just stick with the default
107142
`display: none` CSS. See the [fourth rule of ARIA use](http://www.w3.org/TR/aria-in-html/#fourth-rule-of-aria-use).
108143

144+
###Example
145+
```css
146+
.ng-hide {
147+
display: block;
148+
opacity: 0;
149+
}
150+
```
151+
```html
152+
<div ng-show="false" class="ng-hide" aria-hidden="true"></div>
153+
```
154+
155+
Becomes:
156+
157+
```html
158+
<div ng-show="true" aria-hidden="false"></div>
159+
```
160+
*Note: Child links, buttons or other interactive controls must also be removed from the tab order.*
161+
109162
<h2 id="nghide">ngHide</h2>
110163

111164
>The [ngHide](https://docs.angularjs.org/api/ng/directive/ngHide) directive shows or hides the
@@ -116,33 +169,86 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
116169
`aria-hidden` on the directive when it is hidden or shown, but the content is already hidden with
117170
`display: none`. See explanation for <a href="#ngshow">ngShow</a> when overriding the default CSS.
118171

119-
<h2 id="ngclick">ngClick and ngDblClick</h2>
120-
If `ngClick` or `ngDblClick` is encountered, ngAria will add `tabIndex` if it isn't there already.
121-
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as
122-
`<div>` or `<taco-button>` to enable keyboard access. Conversation is
123-
[currently ongoing](https://github.com/angular/angular.js/issues/9254) about whether ngAria
124-
should also bind `ng-keypress` to be more useful.
172+
<h2 id="ngclick">ngClick and ngDblclick</h2>
173+
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex` if it isn't there already.
174+
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as `div`
175+
or `taco-button` to enable keyboard access. Conversation is currently ongoing about whether ngAria
176+
should also bind `ng-keypress`.
177+
178+
###Example
179+
```html
180+
<div ng-click="toggleMenu()"></div>
181+
```
182+
183+
Becomes:
184+
```html
185+
<div ng-click="toggleMenu()" tabindex="0"></div>
186+
```
187+
*Note: ngAria still requires `ng-keypress` to be added manually to non-native controls like divs.*
125188

126189
<h2 id="ngmessages">ngMessages</h2>
127190

128191
The new ngMessages module makes it easy to display form validation or other messages with priority
129192
sequencing and animation. To expose these visual messages to screen readers,
130193
ngAria injects `aria-live="polite"`, causing them to be read aloud any time a message is shown,
131194
regardless of the user's focus location.
195+
###Example
132196

133-
* * *
197+
```html
198+
<div ng-messages="myForm.myName.$error">
199+
<div ng-message="required">You did not enter a field</div>
200+
<div ng-message="maxlength">Your field is too long</div>
201+
</div>
202+
```
134203

135-
##Disabling attributes
136-
The attribute magic of ngAria may not work for every scenario. To disable individual attributes,
137-
you can use the {@link ngAria.$ariaProvider#config config} method:
204+
Becomes:
138205

206+
```html
207+
<div ng-messages="myForm.myName.$error" aria-live="polite">
208+
<div ng-message="required">You did not enter a field</div>
209+
<div ng-message="maxlength">Your field is too long</div>
210+
</div>
139211
```
140-
angular.module('myApp', ['ngAria'], function config($ariaProvider) {
141-
$ariaProvider.config({
142-
tabindex: false
212+
213+
##Disabling attributes
214+
The attribute magic of ngAria may not work for every scenario. To disable individual attributes,
215+
you can use the {@link ngAria.$ariaProvider#config config} method. Just keep in mind this will
216+
tell ngAria to ignore the attribute globally.
217+
218+
<example module="ngAria_ngDisabledExample" deps="angular-aria.js">
219+
<file name="index.html">
220+
<form>
221+
<div ng-model="someModel" show-attrs>
222+
Div with ngModel, aria-invalid and tabindex disabled
223+
</div>
224+
</form>
225+
<script>
226+
angular.module('ngAria_ngDisabledExample', ['ngAria'], function config($ariaProvider) {
227+
$ariaProvider.config({
228+
ariaInvalid: false,
229+
tabindex: false
230+
});
231+
})
232+
.directive('showAttrs', function() {
233+
return function(scope, el, attrs) {
234+
var pre = document.createElement('pre');
235+
el.after(pre);
236+
scope.$watch(function() {
237+
var attrs = {};
238+
Array.prototype.slice.call(el[0].attributes, 0).forEach(function(item) {
239+
if (item.name !== 'show-attrs') {
240+
attrs[item.name] = item.value;
241+
}
242+
});
243+
return attrs;
244+
}, function(newAttrs, oldAttrs) {
245+
pre.innerText = JSON.stringify(newAttrs, null, 2);
246+
}, true);
247+
}
143248
});
144-
});
145-
```
249+
</script>
250+
</file>
251+
</example>
146252

147253
##Common Accessibility Patterns
148254

@@ -171,6 +277,7 @@ Accessibility best practices that apply to web apps in general also apply to Ang
171277

172278
* [Using ARIA in HTML](http://www.w3.org/TR/aria-in-html/)
173279
* [AngularJS Accessibility at ngEurope](https://www.youtube.com/watch?v=dmYDggEgU-s&list=UUEGUP3TJJfMsEM_1y8iviSQ)
280+
* [Testing with Screen Readers](http://webaim.org/articles/screenreader_testing/)
174281
* [Chrome Accessibility Developer Tools](https://chrome.google.com/webstore/detail/accessibility-developer-t/fpkknkljclfencbdbgkenhalefipecmb?hl=en)
175282
* [W3C Accessibility Testing](http://www.w3.org/wiki/Accessibility_testing)
176283
* [WebAIM](http://webaim.org)

src/ngAria/aria.js

+82-22
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,49 @@
55
* @name ngAria
66
* @description
77
*
8-
* The `ngAria` module provides support for adding <abbr title="Accessible Rich Internet Applications">ARIA</abbr>
9-
* attributes that convey state or semantic information about the application in order to allow assistive technologies
10-
* to convey appropriate information to persons with disabilities.
8+
* The `ngAria` module provides support for common
9+
* [<abbr title="Accessible Rich Internet Applications">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)
10+
* attributes that convey state or semantic information about the application for users
11+
* of assistive technologies, such as screen readers.
1112
*
1213
* <div doc-module-components="ngAria"></div>
1314
*
14-
* # Usage
15-
* To enable the addition of the ARIA tags, just require the module into your application and the tags will
16-
* hook into your ng-show/ng-hide, input, textarea, button, select and ng-required directives and adds the
17-
* appropriate ARIA attributes.
15+
* ## Usage
1816
*
19-
* Currently, the following ARIA attributes are implemented:
17+
* For ngAria to do its magic, simply include the module as a dependency. The directives supported
18+
* by ngAria are:
19+
* `ngModel`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`, `ngDblClick`, and `ngMessages`.
2020
*
21-
* + aria-hidden
22-
* + aria-checked
23-
* + aria-disabled
24-
* + aria-required
25-
* + aria-invalid
26-
* + aria-multiline
27-
* + aria-valuenow
28-
* + aria-valuemin
29-
* + aria-valuemax
30-
* + tabindex
21+
* Below is a more detailed breakdown of the attributes handled by ngAria:
3122
*
32-
* You can disable individual ARIA attributes by using the {@link ngAria.$ariaProvider#config config} method.
23+
* | Directive | Supported Attributes |
24+
* |---------------------------------------------|----------------------------------------------------------------------------------------|
25+
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required |
26+
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
27+
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
28+
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
29+
* | {@link ng.directive:ngClick ngClick} | tabindex |
30+
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
31+
* | {@link module:ngMessages ngMessages} | aria-live |
32+
*
33+
* Find out more information about each directive by reading the
34+
* {@link guide/accessibility ngAria Developer Guide}.
35+
*
36+
* ##Example
37+
* Using ngDisabled with ngAria:
38+
* ```html
39+
* <md-checkbox ng-disabled="disabled">
40+
* ```
41+
* Becomes:
42+
* ```html
43+
* <md-checkbox ng-disabled="disabled" aria-disabled="true">
44+
* ```
45+
*
46+
* ##Disabling Attributes
47+
* It's possible to disable individual attributes added by ngAria with the
48+
* {@link ngAria.$ariaProvider#config config} method. For more details, see the
49+
* {@link guide/accessibility Developer Guide}.
3350
*/
34-
3551
/* global -ngAriaModule */
3652
var ngAriaModule = angular.module('ngAria', ['ng']).
3753
provider('$aria', $AriaProvider);
@@ -42,10 +58,20 @@ var ngAriaModule = angular.module('ngAria', ['ng']).
4258
*
4359
* @description
4460
*
45-
* Used for configuring ARIA attributes.
61+
* Used for configuring the ARIA attributes injected and managed by ngAria.
62+
*
63+
* ```js
64+
* angular.module('myApp', ['ngAria'], function config($ariaProvider) {
65+
* $ariaProvider.config({
66+
* ariaValue: true,
67+
* tabindex: false
68+
* });
69+
* });
70+
*```
4671
*
4772
* ## Dependencies
4873
* Requires the {@link ngAria} module to be installed.
74+
*
4975
*/
5076
function $AriaProvider() {
5177
var config = {
@@ -108,7 +134,41 @@ function $AriaProvider() {
108134
*
109135
* @description
110136
*
111-
* Contains helper methods for applying ARIA attributes to HTML
137+
* The $aria service contains helper methods for applying common
138+
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
139+
*
140+
* ngAria injects common accessibility attributes that tell assistive technologies when HTML
141+
* elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,
142+
* let's review a code snippet from ngAria itself:
143+
*
144+
*```js
145+
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
146+
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled');
147+
* }])
148+
*```
149+
* Shown above, the ngAria module creates a directive with the same signature as the
150+
* traditional `ng-disabled` directive. But this ngAria version is dedicated to
151+
* solely managing accessibility attributes. The internal `$aria` service is used to watch the
152+
* boolean attribute `ngDisabled`. If it has not been explicitly set by the developer,
153+
* `aria-disabled` is injected as an attribute with its value synchronized to the value in
154+
* `ngDisabled`.
155+
*
156+
* Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
157+
* anything to enable this feature. The `aria-disabled` attribute is automatically managed
158+
* simply as a silent side-effect of using `ng-disabled` with the ngAria module.
159+
*
160+
* The full list of directives that interface with ngAria:
161+
* * **ngModel**
162+
* * **ngShow**
163+
* * **ngHide**
164+
* * **ngClick**
165+
* * **ngDblclick**
166+
* * **ngMessages**
167+
* * **ngDisabled**
168+
*
169+
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
170+
* directive.
171+
*
112172
*
113173
* ## Dependencies
114174
* Requires the {@link ngAria} module to be installed.

0 commit comments

Comments
 (0)