Skip to content

Commit 2555d7e

Browse files
committed
feat(tree): improve a11y of the tree nodes, and a11y in mat-tree demo (#9312)
1 parent 36bdae3 commit 2555d7e

File tree

8 files changed

+33
-15
lines changed

8 files changed

+33
-15
lines changed

src/cdk/tree/nested-node.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {CdkTreeNode} from './node';
4040
selector: 'cdk-nested-tree-node',
4141
exportAs: 'cdkNestedTreeNode',
4242
host: {
43+
'[attr.aria-expanded]': 'isExpanded',
4344
'[attr.role]': 'role',
4445
'class': 'cdk-tree-node cdk-nested-tree-node',
4546
},

src/cdk/tree/node.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export class CdkTreeNodeDef<T> {
6767
selector: 'cdk-tree-node',
6868
exportAs: 'cdkTreeNode',
6969
host: {
70+
'[attr.aria-expanded]': 'isExpanded',
71+
'[attr.aria-level]': 'level',
7072
'[attr.role]': 'role',
7173
'class': 'cdk-tree-node',
7274
},
@@ -89,6 +91,14 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
8991
}
9092
protected _data: T;
9193

94+
get isExpanded(): boolean {
95+
return this._tree.treeControl.isExpanded(this._data);
96+
}
97+
98+
get level(): number {
99+
return this._tree.treeControl.getLevel ? this._tree.treeControl.getLevel(this._data) : 0;
100+
}
101+
92102
/**
93103
* The role of the node should be 'group' if it's an internal node,
94104
* and 'treeitem' if it's a leaf node.

src/cdk/tree/tree.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ class FakeDataSource extends DataSource<TestData> {
474474
connect(collectionViewer: CollectionViewer): Observable<TestData[]> {
475475
this.isConnected = true;
476476
const streams = [this._dataChange, collectionViewer.viewChange];
477-
return combineLatest<TestData[]>(streams)
477+
return combineLatest<[TestData[]]>(streams)
478478
.pipe(map(([data]) => {
479479
this.treeControl.dataNodes = data;
480480
return data;

src/cdk/tree/trigger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ export class CdkTreeNodeTrigger<T> {
2828
@Input('cdkTreeNodeTriggerRecursive')
2929
get recursive(): boolean { return this._recursive; }
3030
set recursive(value: boolean) { this._recursive = coerceBooleanProperty(value); }
31-
private _recursive = true;
31+
protected _recursive = true;
3232

33-
constructor(private _tree: CdkTree<T>,
34-
private _treeNode: CdkTreeNode<T>) {}
33+
constructor(protected _tree: CdkTree<T>,
34+
protected _treeNode: CdkTreeNode<T>) {}
3535

3636
_trigger(event: Event): void {
3737
this.recursive

src/demo-app/tree/tree-demo.html

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
</mat-tree-node>
99

1010
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
11-
<mat-icon matTreeNodeTrigger>
12-
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
13-
</mat-icon>
11+
<button mat-icon-button matTreeNodeTrigger
12+
[attr.aria-label]="'toggle ' + node.key">
13+
<mat-icon>
14+
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
15+
</mat-icon>
16+
</button>
1417
{{node.key}} : {{node.value}}
1518
</mat-tree-node>
1619
</mat-tree>
@@ -23,18 +26,21 @@
2326
<mat-card-header>Nested tree</mat-card-header>
2427

2528
<mat-tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl">
26-
<mat-tree-node *matTreeNodeDef="let node" role="treeitem" matTreeNodeTrigger>
29+
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeTrigger>
2730
<li>
2831
<div>{{node.key}}: {{node.value}}</div>
2932
</li>
3033
</mat-tree-node>
3134

32-
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild" role="group">
35+
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
3336
<li>
3437
<div class="mat-tree-node">
35-
<mat-icon matTreeNodeTrigger>
36-
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
37-
</mat-icon>
38+
<button mat-icon-button matTreeNodeTrigger
39+
[attr.aria-label]="'toggle ' + node.key">
40+
<mat-icon>
41+
{{nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
42+
</mat-icon>
43+
</button>
3844
{{node.key}}
3945
</div>
4046
<ul [class]="nestedTreeControl.isExpanded(node) ? '' : 'tree-demo-invisible'">

src/lib/tree/node.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export const _MatNestedTreeNodeMixinBase = mixinTabIndex(mixinDisabled(CdkNested
3535
exportAs: 'matTreeNode',
3636
inputs: ['disabled', 'tabIndex'],
3737
host: {
38+
'[attr.aria-expanded]': 'isExpanded',
39+
'[attr.aria-level]': 'level',
3840
'[attr.role]': 'role',
3941
'class': 'mat-tree-node'
4042
},
@@ -73,6 +75,7 @@ export class MatTreeNodeDef<T> extends CdkTreeNodeDef<T> {
7375
selector: 'mat-nested-tree-node',
7476
exportAs: 'matNestedTreeNode',
7577
host: {
78+
'[attr.aria-expanded]': 'isExpanded',
7679
'[attr.role]': 'role',
7780
'class': 'mat-nested-tree-node',
7881
},

src/lib/tree/tree.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class FakeDataSource extends DataSource<TestData> {
127127
connect(collectionViewer: CollectionViewer): Observable<TestData[]> {
128128
this.isConnected = true;
129129
const streams = [this._dataChange, collectionViewer.viewChange];
130-
return combineLatest<TestData[]>(streams).pipe(map(([data]) => data));
130+
return combineLatest<[TestData[]]>(streams).pipe(map(([data]) => data));
131131
}
132132

133133
disconnect() {

src/lib/tree/tree.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import {MatTreeNodeOutlet} from './outlet';
2121
host: {
2222
'class': 'mat-tree',
2323
'role': 'tree',
24-
'(focus)': 'focus()',
25-
'(keydown)': 'handleKeydown($event)'
2624
},
2725
styleUrls: ['tree.css'],
2826
encapsulation: ViewEncapsulation.None,

0 commit comments

Comments
 (0)