Skip to content

Commit 376c5fc

Browse files
jbogarthydealxhub
authored andcommitted
docs: add accessibility guide (#30851)
PR Close #30851
1 parent 48a7581 commit 376c5fc

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

aio/content/guide/accessibility.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# Accessibility in Angular
2+
3+
The web is used by a wide variety of people, including those who have visual or motor impairments.
4+
A variety of assistive technologies are available that make it much easier for these groups to
5+
interact with web-based software applications.
6+
In addition, designing an application to be more accessible generally improves the user experience for all users.
7+
8+
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals/).
9+
10+
This page discusses best practices for designing Angular applications that
11+
work well for all users, including those who rely on assistive technologies.
12+
13+
## Accessibility attributes
14+
15+
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria)
16+
to provide semantic meaning where it might otherwise be missing.
17+
Use [attribute binding](guide/template-syntax#attribute-binding) template syntax to control the values of accessibility-related attributes.
18+
19+
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA
20+
specification depends specifically on HTML attributes rather than properties on DOM elements.
21+
22+
```html
23+
<!-- Use attr. when binding to an ARIA attribute -->
24+
<button [attr.aria-label]="myActionLabel">...</button>
25+
```
26+
27+
Note that this syntax is only necessary for attribute _bindings_.
28+
Static ARIA attributes require no extra syntax.
29+
30+
```html
31+
<!-- Static ARIA attributes require no extra syntax -->
32+
<button aria-label="Save document">...</button>
33+
```
34+
35+
NOTE:
36+
37+
<div class="alert is-helpful">
38+
39+
By convention, HTML attributes use lowercase names (`tabindex`), while properties use camelCase names (`tabIndex`).
40+
41+
See the [Template Syntax](https://angular.io/guide/template-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
42+
43+
</div>
44+
45+
46+
## Angular UI components
47+
48+
The [Angular Material](https://material.angular.io/) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
49+
The [Component Development Kit (CDK)](https://material.angular.io/cdk/categories) includes the `a11y` package that provides tools to support various areas of accessibility.
50+
For example:
51+
52+
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region. See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
53+
54+
* The `cdkTrapFocus` directive traps Tab-key focus within an element. Use it to create accessible experience for components like modal dialogs, where focus must be constrained.
55+
56+
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.io/cdk/a11y/overview).
57+
58+
59+
### Augmenting native elements
60+
61+
Native HTML elements capture a number of standard interaction patterns that are important to accessibility.
62+
When authoring Angular components, you should re-use these native elements directly when possible, rather than re-implementing well-supported behaviors.
63+
64+
For example, instead of creating a custom element for a new variety of button, you can create a component that uses an attribute selector with a native `<button>` element.
65+
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
66+
67+
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/master/src/material/button/button.ts#L66-L68), [`MatTabNav`](https://github.com/angular/components/blob/master/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L67), [`MatTable`](https://github.com/angular/components/blob/master/src/material/table/table.ts#L17).
68+
69+
### Using containers for native elements
70+
71+
Sometimes using the appropriate native element requires a container element.
72+
For example, the native `<input>` element cannot have children, so any custom text entry components need
73+
to wrap an `<input>` with additional elements.
74+
While you might just include the `<input>` in your custom component's template,
75+
this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
76+
Instead, you can create a container component that uses content projection to include the native control in the
77+
component's API.
78+
79+
You can see [`MatFormField`](https://material.angular.io/components/form-field/overview) as an example of this pattern.
80+
81+
## Case study: Building a custom progress bar
82+
83+
The following example shows how to make a simple progress bar accessible by using host binding to control accessibility-related attributes.
84+
85+
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes. The ARIA attribute `aria-valuenow` is bound to the user's input.
86+
87+
```ts
88+
import { Component, Input } from '@angular/core';
89+
/**
90+
* Example progressbar component.
91+
*/
92+
@Component({
93+
selector: 'example-progressbar',
94+
template: `<div class="bar" [style.width.%]="value"></div>`,
95+
styleUrls: ['./progress-bar.css'],
96+
host: {
97+
// Sets the role for this component to "progressbar"
98+
role: 'progressbar',
99+
100+
// Sets the minimum and maximum values for the progressbar role.
101+
'aria-valuemin': '0',
102+
'aria-valuemax': '0',
103+
104+
// Binding that updates the current value of the progressbar.
105+
'[attr.aria-valuenow]': 'value',
106+
}
107+
})
108+
export class ExampleProgressbar {
109+
/** Current value of the progressbar. */
110+
@Input() value: number = 0;
111+
}
112+
```
113+
114+
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
115+
116+
```html
117+
<label>
118+
Enter an example progress value
119+
<input type="number" min="0" max="100"
120+
[value]="progress" (input)="progress = $event.target.value">
121+
</label>
122+
123+
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
124+
<example-progressbar [value]="progress" aria-label="Example of a progress bar">
125+
</example-progressbar>
126+
```
127+
128+
[See the full example in StackBlitz](https://stackblitz.com/edit/angular-kn5jdi?file=src%2Fapp%2Fapp.component.html).
129+
130+
## Routing and focus management
131+
132+
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus/) in a UI is an important consideration in designing for accessibility.
133+
When using Angular routing, you should decide where page focus goes upon navigation.
134+
135+
To avoid relying solely on visual cues, you need to make sure your routing code updates focus after page navigation.
136+
Use the `NavigationEnd` event from the `Router` service to know when to update
137+
focus.
138+
139+
The following example shows how to find and focus the main content header in the DOM after navigation.
140+
141+
```ts
142+
143+
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
144+
const mainHeader = document.querySelector('#main-content-header')
145+
if (mainHeader) {
146+
mainHeader.focus();
147+
}
148+
});
149+
150+
```
151+
In a real application, the element that receives focus will depend on your specific
152+
application structure and layout.
153+
The focused element should put users in a position to immediately move into the main content that has just been routed into view.
154+
You should avoid situations where focus returns to the `body` element after a route change.
155+
156+
157+
## Additional resources
158+
159+
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
160+
161+
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria/)
162+
163+
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
164+
165+
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
166+
167+
* [Inclusive Components](https://inclusive-components.design/)
168+
169+
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources/)
170+
171+
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web/)
172+
173+
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
174+
175+
* [Codelyzer](http://codelyzer.com/rules/) provides linting rules that can help you make sure your code meets accessibility standards.
176+
177+
Books
178+
179+
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
180+
181+
* "Inclusive Design Patterns", Heydon Pickering

aio/content/navigation.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,11 @@
456456
"title": "Internationalization (i18n)",
457457
"tooltip": "Translate the app's template text into multiple languages."
458458
},
459+
{
460+
"url": "guide/accessibility",
461+
"title": "Accessibility",
462+
"tooltip": "Design apps to be accessible to all users."
463+
},
459464
{
460465
"title": "Service Workers & PWA",
461466
"tooltip": "Angular service workers: Controlling caching of application resources.",

0 commit comments

Comments
 (0)