Skip to content

Commit 6dc9473

Browse files
committed
feat(material/tabs): Refactor MatTabNav to follow the ARIA tabs pattern
by introducing a new tabpanel component.
1 parent a52da04 commit 6dc9473

File tree

13 files changed

+228
-13
lines changed

13 files changed

+228
-13
lines changed

src/components-examples/material/tabs/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {TabGroupLazyLoadedExample} from './tab-group-lazy-loaded/tab-group-lazy-
2020
import {TabGroupStretchedExample} from './tab-group-stretched/tab-group-stretched-example';
2121
import {TabGroupThemeExample} from './tab-group-theme/tab-group-theme-example';
2222
import {TabNavBarBasicExample} from './tab-nav-bar-basic/tab-nav-bar-basic-example';
23+
import {TabNavBarWithPanelExample} from './tab-nav-bar-with-panel/tab-nav-bar-with-panel-example';
2324

2425
export {
2526
TabGroupAlignExample,
@@ -35,6 +36,7 @@ export {
3536
TabGroupStretchedExample,
3637
TabGroupThemeExample,
3738
TabNavBarBasicExample,
39+
TabNavBarWithPanelExample,
3840
};
3941

4042
const EXAMPLES = [
@@ -51,6 +53,7 @@ const EXAMPLES = [
5153
TabGroupStretchedExample,
5254
TabGroupThemeExample,
5355
TabNavBarBasicExample,
56+
TabNavBarWithPanelExample,
5457
];
5558

5659
@NgModule({
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.example-action-button {
2+
margin-top: 8px;
3+
margin-right: 8px;
4+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!-- #docregion mat-tab-nav -->
2+
<nav mat-tab-nav-bar [backgroundColor]="background" [tabPanel]="tabPanel">
3+
<a mat-tab-link *ngFor="let link of links"
4+
(click)="activeLink = link"
5+
[active]="activeLink == link"> {{link}} </a>
6+
<a mat-tab-link disabled>Disabled Link</a>
7+
</nav>
8+
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>
9+
<!-- #enddocregion mat-tab-nav -->
10+
11+
<button mat-raised-button class="example-action-button" (click)="toggleBackground()">
12+
Toggle background
13+
</button>
14+
<button mat-raised-button class="example-action-button" (click)="addLink()">
15+
Add link
16+
</button>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {Component} from '@angular/core';
2+
import {ThemePalette} from '@angular/material/core';
3+
4+
/**
5+
* @title Use of the tab nav bar with the dedicated panel component.
6+
*/
7+
@Component({
8+
selector: 'tab-nav-bar-with-panel-example',
9+
templateUrl: 'tab-nav-bar-with-panel-example.html',
10+
styleUrls: ['tab-nav-bar-with-panel-example.css'],
11+
})
12+
export class TabNavBarWithPanelExample {
13+
links = ['First', 'Second', 'Third'];
14+
activeLink = this.links[0];
15+
background: ThemePalette = undefined;
16+
17+
toggleBackground() {
18+
this.background = this.background ? undefined : 'primary';
19+
}
20+
21+
addLink() {
22+
this.links.push(`Link ${this.links.length + 1}`);
23+
}
24+
}

src/dev-app/mdc-tabs/mdc-tabs-demo.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,13 @@ <h2>Tab nav bar</h2>
127127
[active]="activeLink == link">{{link}}</a>
128128
<a mat-tab-link disabled>Disabled Link</a>
129129
</nav>
130+
131+
<h2>Tab nav bar with panel</h2>
132+
<nav mat-tab-nav-bar [tabPanel]="tabPanel">
133+
<a mat-tab-link *ngFor="let link of links"
134+
(click)="activeLink = link"
135+
[active]="activeLink == link">{{link}}</a>
136+
<a mat-tab-link disabled>Disabled Link</a>
137+
</nav>
138+
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>
130139
</div>

src/dev-app/tabs/tabs-demo.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@ <h3>Tab group stretched</h3>
1818
<tab-group-stretched-example></tab-group-stretched-example>
1919
<h3>Tab group theming</h3>
2020
<tab-group-theme-example></tab-group-theme-example>
21-
<h3>Tab Navigation Bar basic</h3>
21+
<h3>Tab navigation bar basic</h3>
2222
<tab-nav-bar-basic-example></tab-nav-bar-basic-example>
23+
<h3>Tab navigation bar with panel</h3>
24+
<tab-nav-bar-with-panel-example></tab-nav-bar-with-panel-example>

src/material-experimental/mdc-tabs/module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {MatTabLabelWrapper} from './tab-label-wrapper';
1919
import {MatTab} from './tab';
2020
import {MatTabHeader} from './tab-header';
2121
import {MatTabGroup} from './tab-group';
22-
import {MatTabNav, MatTabLink} from './tab-nav-bar/tab-nav-bar';
22+
import {MatTabNav, MatTabNavPanel, MatTabLink} from './tab-nav-bar/tab-nav-bar';
2323

2424
@NgModule({
2525
imports: [
@@ -37,6 +37,7 @@ import {MatTabNav, MatTabLink} from './tab-nav-bar/tab-nav-bar';
3737
MatTab,
3838
MatTabGroup,
3939
MatTabNav,
40+
MatTabNavPanel,
4041
MatTabLink,
4142
],
4243
declarations: [
@@ -45,6 +46,7 @@ import {MatTabNav, MatTabLink} from './tab-nav-bar/tab-nav-bar';
4546
MatTab,
4647
MatTabGroup,
4748
MatTabNav,
49+
MatTabNavPanel,
4850
MatTabLink,
4951

5052
// Private directives, should not be exported.

src/material-experimental/mdc-tabs/public-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export {MatTab} from './tab';
1515
export {MatInkBar} from './ink-bar';
1616
export {MatTabHeader} from './tab-header';
1717
export {MatTabGroup} from './tab-group';
18-
export {MatTabNav, MatTabLink} from './tab-nav-bar/tab-nav-bar';
18+
export {MatTabNav, MatTabNavPanel, MatTabLink} from './tab-nav-bar/tab-nav-bar';
1919

2020
export {
2121
MatTabBodyPositionState,

src/material-experimental/mdc-tabs/tab-nav-bar/tab-nav-bar.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import {takeUntil} from 'rxjs/operators';
5656
templateUrl: 'tab-nav-bar.html',
5757
styleUrls: ['tab-nav-bar.css'],
5858
host: {
59+
'[attr.role]': '_getRole()',
5960
'class': 'mat-mdc-tab-nav-bar mat-mdc-tab-header',
6061
'[class.mat-mdc-tab-header-pagination-controls-enabled]': '_showPaginationControls',
6162
'[class.mat-mdc-tab-header-rtl]': "_getLayoutDirection() == 'rtl'",
@@ -130,12 +131,17 @@ export class MatTabNav extends _MatTabNavBase implements AfterContentInit {
130131
styleUrls: ['tab-link.css'],
131132
host: {
132133
'class': 'mdc-tab mat-mdc-tab-link mat-mdc-focus-indicator',
133-
'[attr.aria-current]': 'active ? "page" : null',
134+
'[attr.aria-controls]': '_getAriaControls()',
135+
'[attr.aria-current]': '_getAriaCurrent()',
134136
'[attr.aria-disabled]': 'disabled',
135-
'[attr.tabIndex]': 'tabIndex',
137+
'[attr.aria-selected]': '_getAriaSelected()',
138+
'[attr.id]': 'id',
139+
'[attr.tabIndex]': '_getTabIndex()',
140+
'[attr.role]': '_getRole()',
136141
'[class.mat-mdc-tab-disabled]': 'disabled',
137142
'[class.mdc-tab--active]': 'active',
138143
'(focus)': '_handleFocus()',
144+
'(keydown)': '_handleKeydown($event)',
139145
},
140146
})
141147
export class MatTabLink extends _MatTabLinkBase implements MatInkBarItem, OnInit, OnDestroy {
@@ -170,3 +176,29 @@ export class MatTabLink extends _MatTabLinkBase implements MatInkBarItem, OnInit
170176
this._foundation.destroy();
171177
}
172178
}
179+
180+
// Increasing integer for generating unique ids for tab nav components.
181+
let nextUniqueId = 0;
182+
183+
/**
184+
* Tab panel component associated with MatTabNav.
185+
*/
186+
@Component({
187+
selector: 'mat-tab-nav-panel',
188+
exportAs: 'matTabNavPanel',
189+
template: '<ng-content></ng-content>',
190+
host: {
191+
'[attr.aria-labelledby]': '_activeTabId',
192+
'[attr.id]': 'id',
193+
'role': 'tabpanel',
194+
},
195+
encapsulation: ViewEncapsulation.None,
196+
changeDetection: ChangeDetectionStrategy.OnPush,
197+
})
198+
export class MatTabNavPanel {
199+
/** Unique id for the tab panel. */
200+
@Input() id = `mat-tab-nav-panel-${nextUniqueId++}`;
201+
202+
/** Id of the active tab in the nav bar. */
203+
_activeTabId?: string;
204+
}

src/material/tabs/public-api.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ export {MatTabHeader, _MatTabHeaderBase} from './tab-header';
2020
export {MatTabLabelWrapper} from './tab-label-wrapper';
2121
export {MatTab, MAT_TAB_GROUP} from './tab';
2222
export {MatTabLabel, MAT_TAB} from './tab-label';
23-
export {MatTabNav, MatTabLink, _MatTabNavBase, _MatTabLinkBase} from './tab-nav-bar/index';
23+
export {
24+
MatTabNav,
25+
MatTabLink,
26+
MatTabNavPanel,
27+
_MatTabNavBase,
28+
_MatTabLinkBase,
29+
} from './tab-nav-bar/index';
2430
export {MatTabContent} from './tab-content';
2531
export {ScrollDirection} from './paginated-tab-header';
2632
export * from './tabs-animations';

0 commit comments

Comments
 (0)