Skip to content

Commit 3229062

Browse files
committed
feat(material/tabs): label & body classes
closes #23685, #9290, #15997
1 parent 7c16258 commit 3229062

File tree

6 files changed

+251
-52
lines changed

6 files changed

+251
-52
lines changed

src/material-experimental/mdc-tabs/tab-group.html

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
[attr.aria-label]="tab.ariaLabel || null"
2020
[attr.aria-labelledby]="(!tab.ariaLabel && tab.ariaLabelledby) ? tab.ariaLabelledby : null"
2121
[class.mdc-tab--active]="selectedIndex == i"
22+
[ngClass]="tab.labelClassList"
2223
[disabled]="tab.disabled"
2324
[fitInkBarToContent]="fitInkBarToContent"
2425
(click)="_handleClick(tab, tabHeader, i)"
@@ -36,12 +37,12 @@
3637
<span class="mdc-tab__content">
3738
<span class="mdc-tab__text-label">
3839
<!-- If there is a label template, use it. -->
39-
<ng-template [ngIf]="tab.templateLabel">
40+
<ng-template [ngIf]="tab.templateLabel" [ngIfElse]="tabTextLabel">
4041
<ng-template [cdkPortalOutlet]="tab.templateLabel"></ng-template>
4142
</ng-template>
4243

4344
<!-- If there is not a label template, fall back to the text label. -->
44-
<ng-template [ngIf]="!tab.templateLabel">{{tab.textLabel}}</ng-template>
45+
<ng-template #tabTextLabel>{{tab.textLabel}}</ng-template>
4546
</span>
4647
</span>
4748
</div>
@@ -52,16 +53,17 @@
5253
[class._mat-animation-noopable]="_animationMode === 'NoopAnimations'"
5354
#tabBodyWrapper>
5455
<mat-tab-body role="tabpanel"
55-
*ngFor="let tab of _tabs; let i = index"
56-
[id]="_getTabContentId(i)"
57-
[attr.tabindex]="(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null"
58-
[attr.aria-labelledby]="_getTabLabelId(i)"
59-
[class.mat-mdc-tab-body-active]="selectedIndex === i"
60-
[content]="tab.content!"
61-
[position]="tab.position!"
62-
[origin]="tab.origin"
63-
[animationDuration]="animationDuration"
64-
(_onCentered)="_removeTabBodyWrapperHeight()"
65-
(_onCentering)="_setTabBodyWrapperHeight($event)">
56+
*ngFor="let tab of _tabs; let i = index"
57+
[id]="_getTabContentId(i)"
58+
[attr.tabindex]="(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null"
59+
[attr.aria-labelledby]="_getTabLabelId(i)"
60+
[class.mat-mdc-tab-body-active]="selectedIndex === i"
61+
[ngClass]="tab.bodyClassList"
62+
[content]="tab.content!"
63+
[position]="tab.position!"
64+
[origin]="tab.origin"
65+
[animationDuration]="animationDuration"
66+
(_onCentered)="_removeTabBodyWrapperHeight()"
67+
(_onCentering)="_setTabBodyWrapperHeight($event)">
6668
</mat-tab-body>
6769
</div>

src/material-experimental/mdc-tabs/tab-group.spec.ts

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ describe('MDC-based MatTabGroup', () => {
4141
TabGroupWithIndirectDescendantTabs,
4242
TabGroupWithSpaceAbove,
4343
NestedTabGroupWithLabel,
44+
TabsWithClassesTestApp,
4445
],
4546
});
4647

@@ -364,7 +365,6 @@ describe('MDC-based MatTabGroup', () => {
364365

365366
expect(contentElements.map(e => e.getAttribute('tabindex'))).toEqual(['1', null, null]);
366367
});
367-
368368
});
369369

370370
describe('aria labelling', () => {
@@ -409,6 +409,7 @@ describe('MDC-based MatTabGroup', () => {
409409

410410
describe('disable tabs', () => {
411411
let fixture: ComponentFixture<DisabledTabsTestApp>;
412+
412413
beforeEach(() => {
413414
fixture = TestBed.createComponent(DisabledTabsTestApp);
414415
});
@@ -482,7 +483,6 @@ describe('MDC-based MatTabGroup', () => {
482483
expect(tabs[0].origin).toBeLessThan(0);
483484
}));
484485

485-
486486
it('should update selected index if the last tab removed while selected', fakeAsync(() => {
487487
const component: MatTabGroup =
488488
fixture.debugElement.query(By.css('mat-tab-group')).componentInstance;
@@ -500,7 +500,6 @@ describe('MDC-based MatTabGroup', () => {
500500
expect(component.selectedIndex).toBe(numberOfTabs - 2);
501501
}));
502502

503-
504503
it('should maintain the selected tab if a new tab is added', () => {
505504
fixture.detectChanges();
506505
const component: MatTabGroup =
@@ -517,7 +516,6 @@ describe('MDC-based MatTabGroup', () => {
517516
expect(component._tabs.toArray()[2].isActive).toBe(true);
518517
});
519518

520-
521519
it('should maintain the selected tab if a tab is removed', () => {
522520
// Select the second tab.
523521
fixture.componentInstance.selectedIndex = 1;
@@ -565,7 +563,6 @@ describe('MDC-based MatTabGroup', () => {
565563

566564
expect(fixture.componentInstance.handleSelection).not.toHaveBeenCalled();
567565
}));
568-
569566
});
570567

571568
describe('async tabs', () => {
@@ -935,6 +932,7 @@ class SimpleTabsTestApp {
935932
animationDone() { }
936933
}
937934

935+
938936
@Component({
939937
template: `
940938
<mat-tab-group class="tab-group"
@@ -965,6 +963,7 @@ class SimpleDynamicTabsTestApp {
965963
}
966964
}
967965

966+
968967
@Component({
969968
template: `
970969
<mat-tab-group class="tab-group" [(selectedIndex)]="selectedIndex">
@@ -990,8 +989,8 @@ class BindedTabsTestApp {
990989
}
991990
}
992991

992+
993993
@Component({
994-
selector: 'test-app',
995994
template: `
996995
<mat-tab-group class="tab-group">
997996
<mat-tab>
@@ -1014,6 +1013,7 @@ class DisabledTabsTestApp {
10141013
isDisabled = false;
10151014
}
10161015

1016+
10171017
@Component({
10181018
template: `
10191019
<mat-tab-group class="tab-group">
@@ -1059,7 +1059,6 @@ class TabGroupWithSimpleApi {
10591059

10601060

10611061
@Component({
1062-
selector: 'nested-tabs',
10631062
template: `
10641063
<mat-tab-group>
10651064
<mat-tab label="One">Tab one content</mat-tab>
@@ -1077,8 +1076,8 @@ class NestedTabs {
10771076
@ViewChildren(MatTabGroup) groups: QueryList<MatTabGroup>;
10781077
}
10791078

1079+
10801080
@Component({
1081-
selector: 'template-tabs',
10821081
template: `
10831082
<mat-tab-group>
10841083
<mat-tab label="One">
@@ -1091,11 +1090,11 @@ class NestedTabs {
10911090
</mat-tab>
10921091
</mat-tab-group>
10931092
`,
1094-
})
1095-
class TemplateTabs {}
1093+
})
1094+
class TemplateTabs {}
10961095

10971096

1098-
@Component({
1097+
@Component({
10991098
template: `
11001099
<mat-tab-group>
11011100
<mat-tab [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby"></mat-tab>
@@ -1160,6 +1159,7 @@ class TabGroupWithInkBarFitToContent {
11601159
fitInkBarToContent = true;
11611160
}
11621161

1162+
11631163
@Component({
11641164
template: `
11651165
<div style="height: 300px; background-color: aqua">
@@ -1202,3 +1202,31 @@ class TabGroupWithSpaceAbove {
12021202
})
12031203
class NestedTabGroupWithLabel {
12041204
}
1205+
1206+
1207+
@Component({
1208+
template: `
1209+
<mat-tab-group class="tab-group">
1210+
<mat-tab label="Tab One">
1211+
Tab one content
1212+
</mat-tab>
1213+
<mat-tab label="Tab Two" [class]="labelClassList">
1214+
Tab two content
1215+
</mat-tab>
1216+
<mat-tab label="Tab Three" [bodyClass]="bodyClassList">
1217+
Tab three content
1218+
</mat-tab>
1219+
<mat-tab label="Tab Four" [class]="labelClassList" [bodyClass]="bodyClassList">
1220+
Tab four content
1221+
</mat-tab>
1222+
<mat-tab label="Tab Five" class="hardcoded label classes" bodyClass="hardcoded body classes">
1223+
Tab five content
1224+
</mat-tab>
1225+
</mat-tab-group>
1226+
`,
1227+
})
1228+
class TabsWithClassesTestApp {
1229+
@ViewChildren(MatTab) tabs: QueryList<MatTab>;
1230+
labelClassList?: string | string[];
1231+
bodyClassList?: string | string[];
1232+
}

src/material/tabs/tab-group.html

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
[disablePagination]="disablePagination"
55
(indexFocused)="_focusChanged($event)"
66
(selectFocusedIndex)="selectedIndex = $event">
7-
<div class="mat-tab-label mat-focus-indicator" role="tab" matTabLabelWrapper mat-ripple cdkMonitorElementFocus
7+
<div class="mat-tab-label mat-focus-indicator" role="tab" matTabLabelWrapper mat-ripple
8+
cdkMonitorElementFocus
89
*ngFor="let tab of _tabs; let i = index"
910
[id]="_getTabLabelId(i)"
1011
[attr.tabIndex]="_getTabIndex(tab, i)"
@@ -15,6 +16,7 @@
1516
[attr.aria-label]="tab.ariaLabel || null"
1617
[attr.aria-labelledby]="(!tab.ariaLabel && tab.ariaLabelledby) ? tab.ariaLabelledby : null"
1718
[class.mat-tab-label-active]="selectedIndex == i"
19+
[ngClass]="tab.labelClassList"
1820
[disabled]="tab.disabled"
1921
[matRippleDisabled]="tab.disabled || disableRipple"
2022
(click)="_handleClick(tab, tabHeader, i)"
@@ -23,12 +25,12 @@
2325

2426
<div class="mat-tab-label-content">
2527
<!-- If there is a label template, use it. -->
26-
<ng-template [ngIf]="tab.templateLabel">
28+
<ng-template [ngIf]="tab.templateLabel" [ngIfElse]="tabTextLabel">
2729
<ng-template [cdkPortalOutlet]="tab.templateLabel"></ng-template>
2830
</ng-template>
2931

3032
<!-- If there is not a label template, fall back to the text label. -->
31-
<ng-template [ngIf]="!tab.templateLabel">{{tab.textLabel}}</ng-template>
33+
<ng-template #tabTextLabel>{{tab.textLabel}}</ng-template>
3234
</div>
3335
</div>
3436
</mat-tab-header>
@@ -38,16 +40,17 @@
3840
[class._mat-animation-noopable]="_animationMode === 'NoopAnimations'"
3941
#tabBodyWrapper>
4042
<mat-tab-body role="tabpanel"
41-
*ngFor="let tab of _tabs; let i = index"
42-
[id]="_getTabContentId(i)"
43-
[attr.tabindex]="(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null"
44-
[attr.aria-labelledby]="_getTabLabelId(i)"
45-
[class.mat-tab-body-active]="selectedIndex === i"
46-
[content]="tab.content!"
47-
[position]="tab.position!"
48-
[origin]="tab.origin"
49-
[animationDuration]="animationDuration"
50-
(_onCentered)="_removeTabBodyWrapperHeight()"
51-
(_onCentering)="_setTabBodyWrapperHeight($event)">
43+
*ngFor="let tab of _tabs; let i = index"
44+
[id]="_getTabContentId(i)"
45+
[attr.tabindex]="(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null"
46+
[attr.aria-labelledby]="_getTabLabelId(i)"
47+
[class.mat-tab-body-active]="selectedIndex === i"
48+
[ngClass]="tab.bodyClassList"
49+
[content]="tab.content!"
50+
[position]="tab.position!"
51+
[origin]="tab.origin"
52+
[animationDuration]="animationDuration"
53+
(_onCentered)="_removeTabBodyWrapperHeight()"
54+
(_onCentering)="_setTabBodyWrapperHeight($event)">
5255
</mat-tab-body>
5356
</div>

0 commit comments

Comments
 (0)