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

Commit 7b82ca6

Browse files
committed
chore(accessibility): Add aria attributes to aid screen reader flow
1 parent e704d54 commit 7b82ca6

File tree

13 files changed

+98
-37
lines changed

13 files changed

+98
-37
lines changed

src/app/material-docs-app.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {Component, ViewEncapsulation} from '@angular/core';
2+
import {Title} from '@angular/platform-browser';
23
import {Router} from '@angular/router';
34

45

@@ -14,10 +15,34 @@ import {Router} from '@angular/router';
1415
export class MaterialDocsApp {
1516
isDarkTheme = false;
1617
showShadow = false;
18+
baseTitle = 'Angular Material';
1719

18-
constructor(router: Router) {
20+
constructor(router: Router, private _titleService: Title) {
1921
router.events.subscribe(data => {
2022
this.showShadow = data.url.startsWith('/components');
23+
this._setTitle(window.location.pathname);
2124
});
2225
}
26+
27+
private _setTitle(pathname) {
28+
const title = this._getTitle(pathname);
29+
title ?
30+
this._titleService.setTitle(`${this.baseTitle} - ${this._capitalizeTitle(title)}`) :
31+
this._titleService.setTitle(this.baseTitle);
32+
}
33+
34+
private _getTitle(pathname) {
35+
return pathname.split('/').filter(Boolean).pop();
36+
}
37+
38+
private _trimFilename(filename) {
39+
const isFilenameRegex = new RegExp(/.+\./g);
40+
return ~filename.search(isFilenameRegex) ?
41+
filename.match(isFilenameRegex)[0].replace('.', '') :
42+
filename;
43+
}
44+
45+
private _capitalizeTitle(title) {
46+
return title[0].toUpperCase() + this._trimFilename(title.slice(1));
47+
}
2348
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<div class="docs-component-category-list">
2-
<md-card
3-
*ngFor="let category of docItems.getItemsInCategories()"
4-
class="docs-component-category-list-card"
5-
[routerLink]="['/components/category/', category.id]">
6-
<md-card-title>{{category.name}}</md-card-title>
7-
<p class="docs-component-category-list-card-summary">{{category.summary}}</p>
8-
<div class="docs-component-category-list-card-image"
9-
[style.backgroundImage]="'url(\'../../../assets/img/component-categories/' + category.id +'.svg\')'">
10-
</div>
11-
</md-card>
2+
<a
3+
*ngFor="let category of docItems.getItemsInCategories()"
4+
[routerLink]="['/components/category/', category.id]">
5+
<md-card class="docs-component-category-list-card">
6+
<md-card-title>{{category.name}}</md-card-title>
7+
<p class="docs-component-category-list-card-summary">{{category.summary}}</p>
8+
<div class="docs-component-category-list-card-image"
9+
[style.backgroundImage]="'url(\'../../../assets/img/component-categories/' + category.id +'.svg\')'">
10+
</div>
11+
</md-card>
12+
</a>
1213
</div>

src/app/pages/component-page-header/component-page-header.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
<md-icon>menu</md-icon>
44
</button>
55

6-
<h1>{{getTitle()}} </h1>
6+
<h1 focusElement>{{getTitle()}} </h1>
77
</div>

src/app/pages/component-sidenav/component-sidenav.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<md-sidenav-container class="docs-component-viewer-sidenav-container">
2-
<md-sidenav #sidenav class="docs-component-viewer-sidenav"
2+
<md-sidenav aria-label="Component navigation" role="navigation" #sidenav class="docs-component-viewer-sidenav"
33
[opened]="!isScreenSmall()"
44
[mode]="isScreenSmall() ? 'over' : 'side'">
5-
<nav *ngFor="let category of docItems.getItemsInCategories()">
6-
<h3>{{category.name}}</h3>
5+
<nav [attr.aria-labelledby]="category.id + '-id'" *ngFor="let category of docItems.getItemsInCategories()">
6+
<h3 tabindex="0" id="{{category.id}}-id">{{category.name}}</h3>
77
<ul>
88
<li *ngFor="let component of category.items">
99
<a [routerLink]="['/components/component/', component.id]"
@@ -15,7 +15,7 @@ <h3>{{category.name}}</h3>
1515
</nav>
1616
</md-sidenav>
1717

18-
<div class="docs-component-sidenav-content">
18+
<div role="main" class="docs-component-sidenav-content">
1919
<component-page-header (toggleSidenav)="sidenav.toggle()"></component-page-header>
2020
<router-outlet></router-outlet>
2121
<app-footer></app-footer>
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
<!-- TODO(jelbourn): turn this into nav tabs -->
22
<md-tab-group class="docs-component-viewer-tabbed-content"
33
(selectedIndexChange)="overviewViewer.releadLiveExamples()">
4-
<md-tab label="OVERVIEW">
5-
<doc-viewer #overviewViewer
4+
<md-tab id="overviewViewerTab" aria-controls="overviewViewer" role="tab" label="OVERVIEW">
5+
<doc-viewer aria-labelledby="overviewViewerTab" id="overviewViewer" role="tabpanel" #overviewViewer
66
documentUrl="/assets/documents/overview/{{componentDocItem.id}}.html"
77
class="docs-component-view-text-content">
88
</doc-viewer>
99
</md-tab>
1010

11-
<md-tab label="API REFERENCE">
12-
<doc-viewer documentUrl="/assets/documents/api/{{componentDocItem.id}}.html"
11+
<md-tab id="apiViewerTab" aria-controls="apiViewer" role="tab" label="API REFERENCE">
12+
<doc-viewer aria-labelledby="apiViewerTab" id="apiViewer" role="tabpanel" documentUrl="/assets/documents/api/{{componentDocItem.id}}.html"
1313
class="docs-component-view-text-content"></doc-viewer>
1414
</md-tab>
1515

16-
<md-tab label="EXAMPLES">
16+
<md-tab id="exampleViewerTab" aria-controls="exampleViewer" role="tab" label="EXAMPLES">
1717

18-
<example-viewer *ngFor="let example of componentDocItem.examples" [example]="example">
19-
</example-viewer>
18+
<div id="exmapleViewer" aria-labelledby="exampleViewerTab" role="tabpanel">
19+
<example-viewer *ngFor="let example of componentDocItem.examples" [example]="example">
20+
</example-viewer>
21+
</div>
2022

2123
</md-tab>
2224
</md-tab-group>
+11-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
<div class="docs-primary-header">
2-
<h1>Guides</h1>
3-
</div>
4-
<md-list class="docs-guide-list-item">
5-
<a md-list-item
6-
*ngFor="let guide of guideItems.getAllItems()"
7-
[routerLink]="['/guide/', guide.id]">
1+
<div class="docs-guides-container" role="main">
2+
<div class="docs-primary-header">
3+
<h1 focusElement>Guides</h1>
4+
</div>
5+
<md-list class="docs-guide-list-item">
6+
<a md-list-item
7+
*ngFor="let guide of guideItems.getAllItems()"
8+
[routerLink]="['/guide/', guide.id]">
89
{{guide.name}}
9-
</a>
10-
</md-list>
10+
</a>
11+
</md-list>
12+
</div>
1113

1214
<app-footer></app-footer>

src/app/pages/guide-list/guide-list.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
:host {
1+
:host, .docs-guides-container {
22
display: flex;
33
flex-direction: column;
44
flex-grow: 1;

src/app/pages/guide-viewer/guide-viewer.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="docs-primary-header">
2-
<h1>{{guide.name}}</h1>
2+
<h1 focusElement>{{guide.name}}</h1>
33
</div>
44

55
<doc-viewer class="docs-guide-content" [documentUrl]="guide.document"></doc-viewer>

src/app/pages/homepage/homepage.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h2> Material Design components for Angular apps</h2>
1010
</div>
1111
</header>
1212

13-
<div class="docs-homepage-promo">
13+
<div role="main" class="docs-homepage-promo">
1414
<div class="docs-homepage-row">
1515
<div class="docs-homepage-promo-img">
1616
<img src="../assets/img/homepage/sprintzerotoapp.svg" alt="Sprint from Zero to App" />

src/app/shared/example-viewer/example-viewer.html

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<div class="docs-example-viewer-title-spacer">{{exampleData?.title}}</div>
44

55
<button md-icon-button type="button" (click)="toggleSourceView()"
6+
aria-label="Toggle View Source"
67
[mdTooltip]="'View source'">
78
<md-icon>
89
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fit="" preserveAspectRatio="xMidYMid meet" focusable="false">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {Renderer, Directive, ElementRef} from '@angular/core';
2+
3+
4+
@Directive({
5+
selector: '[focusElement]'
6+
})
7+
8+
export class FocusElementDirective {
9+
10+
constructor(
11+
private _element: ElementRef,
12+
private _renderer: Renderer
13+
) { }
14+
15+
ngAfterViewInit() {
16+
// Add tabindex 0 so element is focusable by keyboard
17+
this
18+
._renderer
19+
.setElementAttribute(this._element.nativeElement, 'tabindex', '0');
20+
21+
// Focus host element after view loads
22+
// so screen readers will be alerted
23+
// the page has changed.
24+
this._element.nativeElement.focus();
25+
}
26+
}

src/app/shared/plunker/plunker-button.html

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<!-- TODO: change the template to be plunker icon -->
22
<div [mdTooltip]="isDisabled ? 'Building Plunker example...' : 'Edit in Plunker'">
33
<button md-icon-button type="button"
4+
aria-label="Edit in Plunker"
45
(click)="openPlunker()"
56
[disabled]="isDisabled">
67
<md-icon>

src/app/shared/shared-module.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {HttpModule} from '@angular/http';
33
import {DocViewer} from './doc-viewer/doc-viewer';
44
import {ExampleViewer} from './example-viewer/example-viewer';
55
import {DocumentationItems} from './documentation-items/documentation-items';
6+
import {FocusElementDirective} from './focus-element/focus-element';
67
import {NavBar} from './navbar/navbar';
78
import {MaterialModule} from '@angular/material';
89
import {BrowserModule} from '@angular/platform-browser';
@@ -18,8 +19,10 @@ import {GuideItems} from './guide-items/guide-items';
1819
BrowserModule,
1920
MaterialModule,
2021
],
21-
declarations: [DocViewer, ExampleViewer, NavBar, PlunkerButton],
22-
exports: [DocViewer, ExampleViewer, NavBar, PlunkerButton],
22+
declarations: [DocViewer, ExampleViewer, NavBar,
23+
PlunkerButton, FocusElementDirective],
24+
exports: [DocViewer, ExampleViewer, NavBar,
25+
PlunkerButton, FocusElementDirective],
2326
providers: [DocumentationItems, GuideItems],
2427
entryComponents: [
2528
ExampleViewer,

0 commit comments

Comments
 (0)