Skip to content

Commit

Permalink
perf(cdk/table): Optimize a11y role logic in CdkCell.
Browse files Browse the repository at this point in the history
  • Loading branch information
kseamon committed Jan 5, 2024
1 parent a8b8e62 commit de794e4
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 6 deletions.
10 changes: 4 additions & 6 deletions src/cdk/table/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,8 @@ export class CdkHeaderCell extends BaseCdkCell {
export class CdkFooterCell extends BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
super(columnDef, elementRef);
if (columnDef._table?._elementRef.nativeElement.nodeType === 1) {
const tableRole = columnDef._table._elementRef.nativeElement.getAttribute('role');
const role = tableRole === 'grid' || tableRole === 'treegrid' ? 'gridcell' : 'cell';
const role = columnDef._table?._cellRole;
if (role) {
elementRef.nativeElement.setAttribute('role', role);
}
}
Expand All @@ -210,9 +209,8 @@ export class CdkFooterCell extends BaseCdkCell {
export class CdkCell extends BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
super(columnDef, elementRef);
if (columnDef._table?._elementRef.nativeElement.nodeType === 1) {
const tableRole = columnDef._table._elementRef.nativeElement.getAttribute('role');
const role = tableRole === 'grid' || tableRole === 'treegrid' ? 'gridcell' : 'cell';
const role = columnDef._table?._cellRole;
if (role) {
elementRef.nativeElement.setAttribute('role', role);
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/cdk/table/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,27 @@ describe('CdkTable', () => {
]);
});

it('defaults to table role in native HTML table', () => {
const fixture = createComponent(NativeHtmlTableApp);
const tableElement = fixture.nativeElement.querySelector('table');
fixture.detectChanges();
expect(tableElement.getAttribute('role')).toBe('table');

expect(getHeaderRows(tableElement)[0].getAttribute('role')).toBe('row');
const header = getHeaderRows(tableElement)[0];
getHeaderCells(header).forEach(cell => {
expect(cell.getAttribute('role')).toBe('columnheader');
});

getRows(tableElement).forEach(row => {
expect(row.getAttribute('role')).toBe('row');
getCells(row).forEach(cell => {
// Native role of TD elements is row.
expect(cell.getAttribute('role')).toBe(null);
});
});
});

it('should be able to nest tables', () => {
const thisFixture = createComponent(NestedHtmlTableApp);
thisFixture.detectChanges();
Expand Down
13 changes: 13 additions & 0 deletions src/cdk/table/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,19 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
/** Whether the no data row is currently showing anything. */
private _isShowingNoDataRow = false;

/** Aria role to apply to the table's cells based on the table's own role. */
get _cellRole(): string | null {
if (this._cellRoleInternal === undefined) {
// Perform this lazily in case the table's role was updated by a directive after construction.
const role = this._elementRef.nativeElement.getAttribute('role');
const cellRole = role === 'grid' || role === 'treegrid' ? 'gridcell' : 'cell';
this._cellRoleInternal = this._isNativeHtmlTable && cellRole === 'cell' ? null : cellRole;
}

return this._cellRoleInternal;
}
private _cellRoleInternal: string | null | undefined = undefined;

/**
* Tracking function that will be used to check the differences in data changes. Used similarly
* to `ngFor` `trackBy` function. Optimize row operations by identifying a row based on its data
Expand Down
1 change: 1 addition & 0 deletions tools/public_api_guard/cdk/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
addFooterRowDef(footerRowDef: CdkFooterRowDef): void;
addHeaderRowDef(headerRowDef: CdkHeaderRowDef): void;
addRowDef(rowDef: CdkRowDef<T>): void;
get _cellRole(): string | null;
// (undocumented)
protected readonly _changeDetectorRef: ChangeDetectorRef;
// (undocumented)
Expand Down

0 comments on commit de794e4

Please sign in to comment.