Grid WAI-ARIA Support
Out of the box, the Kendo UI for Angular Grid provides extensive accessibility support and enables users with disabilities to acquire complete control over its features.
The Grid is compliant with the Web Content Accessibility Guidelines (WCAG) 2.2 AA standards and Section 508 requirements, follows the Web Accessibility Initiative - Accessible Rich Internet Applications (WAI-ARIA) best practices for implementing the keyboard navigation for its component
role, provides options for managing its focus and is tested against the most popular screen readers.
WAI-ARIA
This section lists the selectors, attributes, and behavior patterns supported by the component and its composite elements, if any.
The Grid is a composite component that consists of 4 logically separated structural elements:
- Toolbar (
role=toolbar
); - Group header (
role=toolbar
); - Data Grid (
role=grid
); - Pager (
role=application
);
Grid Toolbar
Grid Toolbar follows the specification of the ToolBar component.
ToolBar accessibility specification
Selector | Attribute | Usage |
---|---|---|
.k-grid-toolbar | role=toolbar | The toolbar is a collection of command buttons and inputs. |
aria-label | Clarifies the purpose of the toolbar. | |
aria-controls=.k-grid-aria-root id | Pointing to the id of the element with role=grid . |
Grid Grouping Header
Grid Grouping Header follows the specification of the ToolBar component.
ToolBar accessibility specification
Selector | Attribute | Usage |
---|---|---|
.k-grouping-header | role=toolbar | The Grouping header is a ToolBar (collection of buttons). |
aria-label | Clarifies the purpose of the header. | |
aria-controls=.k-grid-aria-root id | Pointing to the id of the element with role=grid . | |
.k-grouping-header .k-chip-list .k-chip | role=button | If the element used is not <button> , then the role must be specified. |
.k-grouping-header .k-chip-list | role=none/ | The ChipList default listbox role is removed to keep the toolbar --> button roles hierarchy. |
title | Present on the element or its child if sorting is enabled for that field. |
Data Grid (excluding Toolbars and Pager)
The element with role=grid
must not include the ToolBar and the Pager elements as those do not belong to the role=grid
element itself.
Grid element
Selector | Attribute | Usage |
---|---|---|
.k-grid:not(.k-treelist) .k-grid-aria-root | role=grid | The role specifies the element is a Data Grid. |
.k-grid-aria-root | aria-colcount | The total number of columns in the Grid. Needed only for Virtual columns and Hidden columns scenarios, when not all columns are rendered in the DOM. If the total number of columns is unknown, the value of aria-colcount must be set to -1. |
aria-rowcount | The total number of rows in the table (header rows + master rows + detail rows + data rows + footer rows + aggregates rows). Needed only when Paging (and more that 1 page is present in the component), Virtual rows, or Master/Detail rows (Hierarchical Grid, Detail Template Grid) are enabled. If data is also Grouped, the proper number of all rows could not be calculated. In that case the value must be set to -1. |
In scenarios when master and detail rows are present in the Grid (Hierarchical Grid, Detail Template Grid), the aria-rowcount
(the total number of rows) must be calculated: 2 * (total number of items) + header rows + footer rows. That is because for each item in the Grid there is a master row and a detail row duplicating this way the number of rows.
If the Grid is composed of a single table (there is no separate <table>
element for its header), no role
attributes should be set on its inner elements(<thead>
, <body>
, <tr>
, <th>
, and <td>
). Their semantic meaning will be used instead.
Grid header
Selector | Attribute | Usage |
---|---|---|
.k-grid-header-wrap>table | role=presentation/none | Negates the default semantic role of the <table> element. |
.k-grid-header-wrap>table>thead | role=rowgroup | Required as the owner <table> element has its semantic role removed. |
.k-grid-header-wrap>table>thead>tr | role=row | Required as the owner <table> element has its semantic role removed. |
aria-rowindex | Row number including all headers, data (including master and detail) rows, and footers starting from 1. Needed only when Paging (and more that 1 page is present in the component), Virtual rows, or Master/Detail rows (Hierarchical Grid, Detail Template Grid) are enabled. If data is also Grouped, the proper indexing could not be calculated. Hence, the attribute must not be set. | |
.k-grid-header-wrap>table>thead>tr>th:not(.k-hierarchy-cell):not(.k-group-cell):not(.k-drag-cell) | role=columnheader | Required as the owner <table> element has its semantic role removed. |
aria-sort=none/ascending/descending | Present if sorting is enabled for that column. | |
title or aria-label | Present on the element or its child if sorting is enabled for that field. | |
aria-colindex | Col number, based on leaf columns, starting from 1. Needed only for Virtual columns and Hidden columns scenarios, when not all columns are rendered in the DOM. Otherwise, can be interpreted from the DOM structure. Can be calculated by summing previous columns colspans. | |
aria-haspopup=dialog | The attribute must be present if the column has a ColumnMenu. | |
aria-haspopup=dialog | The attribute must be present if the column has a FilterMenu and no ColumnMenu. |
Grid filter row
Even if part of the <thead>
, the Filter row must be composed of <td>
elements.
Selector | Attribute | Usage |
---|---|---|
.k-grid-header-wrap>table>thead>tr.k-filter-row>td | role=gridcell | Required as the owner <table> element has its semantic role removed. |
aria-label | Has a label indicating that the cell is part of a filter row. |
Grid filter menu
Implements the FilterMenu specification.
-
The FilterMenu Button/Header
Selector Attribute Usage .k-grid-filter-menu
aria-haspopup=dialog
Specifies that the button opens a dialog. aria-expanded=true/false
Announces the current state of the popup. aria-controls=.k-popup.k-grid-filter-popup id
Points to the popup that the button toggles. .k-header.k-filterable
aria-haspopup=dialog
Specifies that the header cell opens a dialog. aria-expanded=true/false
Announces the current state of the popup. aria-controls=.k-popup.k-grid-filter-popup id
Points to the popup that the button toggles. aria-keyshortcuts=Alt + ArrowDown
Announces the available filter-menu shortcut. -
The FilterMenu Popup
Selector Attribute Usage .k-popup.k-grid-filter-popup
id
Unique and deterministic id linked to the button or header cell aria-controls attribute. role=dialog
Sets the dialog role of the popup. aria-label
Contains descriptive information about the filter menu purpose - e.g. 'Column Title Filter Menu' -
The FilterMenu Popup Content
All internal elements and components follow their respective specification rules, and additionally have suitable aria-label attributes, describing what menu they are part of.
-
Adaptive Mode
When the FilterMenu is in adaptive mode, the popup element follows the specifications of the ActionSheet component.
Grid column menu
Implements the ColumnMenu specification.
-
The ColumnMenu Button/Header
Selector Attribute Usage .k-grid-column-menu
role=button
Specifies that column menu element has role button. aria-haspopup=dialog
Specifies that the button opens a dialog. aria-expanded=true/false
Announces the current state of the popup. aria-controls=.k-popup.k-grid-columnmenu-popup id
Points to the popup that the button toggles. .k-header:has(.k-grid-column-menu)
aria-haspopup=dialog
Specifies that the header cell opens a dialog. aria-expanded=true/false
Announces the current state of the popup. aria-controls=.k-popup.k-grid-columnmenu-popup id
Points to the popup that the button toggles. aria-keyshortcuts=Alt + ArrowDown
Announces the available column-menu shortcut. -
The ColumnMenu Popup
Selector Attribute Usage .k-popup.k-grid-columnmenu-popup
id
Unique and deterministic id linked to the button or header cell aria-controls attribute. role=dialog
Sets the dialog role of the popup. aria-label
Contains descriptive information about the column menu purpose - e.g. 'Column Title Column Menu' -
ColumnMenu Popup ExpandableContent
Selector Attribute Usage .k-columnmenu-item
role=button
Sets column menu item role to button tabindex=0
Sets column menu item tabindex .k-expander .k-columnmenu-item
aria-expanded=true/false
Sets the expanded state of an expandable item aria-controls
Points to id attribute of the content whose visibility the expandable item controls. .k-expander .k-columnmenu-item-content
id
Unique and deterministic id linked to the aria-controls attribute of the corresponding expandable item. .k-column-list
role=listbox
Sets the listbox role of the list of columns wrapper. aria-multiselectable=true
Specifies that the list is multiselectable. .k-column-list .k-column-list-item
role=option
Sets the option role of the list item. aria-checked=true/false
Sets the checked state of list item. tabindex=0/-1
Sets the tabindex depending on the item's focused state. .k-column-list-item .k-checkbox
tabindex=-1
Removes the default focus behavior of the checkbox. aria-hidden=true
Hides the checkbox from the assistive technologies, as its accessibility is implemented by the item wrapper. -
Other ColumnMenu Popup Content
All internal elements and components follow their respective specification rules, and additionally have suitable aria-label attributes, describing what menu they are part of.
-
Adaptive Mode
When the component is in adaptive mode, the popup element follows the specifications of the ActionSheet component.
Grid content
Selector | Attribute | Usage |
---|---|---|
.k-grid-content>table | role=none/presentation | Negates the default semantic role of the <table> element. |
.k-grid-content>table>tbody | role=rowgroup | Required as the owner <table> element has its semantic role removed. |
.k-grid-content>table>tbody>tr | role=row | Required as the owner <table> element has its semantic role removed. |
aria-rowindex | Row number including all headers, data (including master and detail) rows, and footers starting from 1. Needed only when Paging (and more that 1 page is present in the component), Virtual rows, or Master/Detail rows (Hierarchical Grid, Detail Template Grid) are enabled. If data is also Grouped, the proper indexing could not be calculated. Hence, the attribute must not be set. In scenarios when master and detail rows are present in the Grid (Hierarchical Grid, Detail Template Grid), both master and detail rows must always be indexed. For example, if the first master row has aria-rowindex=2 , even if its detail row is not present in the DOM, the next master row must have aria-rowindex=4 . When rendered, the detail row must receive the missing index between the two master rows. In this example it would be aria-rowindex=3 . | |
.k-grid-content tr.k-selected | aria-selected=true | Set on the currently selected row(s). Only used wen selection mode is set to row . |
.k-grid-content>table>tbody>tr>td | role=gridcell | Required as the owner <table> element has its semantic role removed. |
aria-colindex | Col number, based on leaf columns, starting from 1. Needed only for Virtual columns and Hidden columns scenarios, when not all columns are rendered in the DOM. Otherwise, can be interpreted from the DOM structure. Can be calculated by summing previous columns colspans. | |
td.k-selected | aria-selected=true | Set on the currently selected cell(s). Only used when selection mode is set to cell. |
.k-master-row .k-hierarchy-cell,.k-grouping-row>td | aria-expanded=true/false | Optionally for cells holding grouping criteria values and for Master row cells in Detail template scenario. |
.k-drag-cell | aria-label | Must be present in a Drag Row scenario on the cell containing the drag handle. |
.k-grid-header-locked .k-grid-header-table .k-table-row | aria-owns | When there are locked columns, the rows from the locked header table should own the cells from the corresponding non-locked header table rows. Value should be a space-separated list of id s. |
.k-grid-content-locked .k-grid-table .k-table-row | aria-owns | When there are locked columns, the rows from the locked content table should own the cells from the corresponding non-locked content table rows. Value should be a space-separated list of id s. |
.k-grid-header-wrap .k-grid-header-table .k-table-row | role=presentation/none | When there are locked columns, the rows from the non-locked header table should have their default semantic role removed, as their children are owned by the corresponding row from the locked table. |
.k-grid-content .k-grid-table .k-table-row | role=presentation/none | When there are locked columns, the rows from the non-locked content table should have their default semantic role removed, as their children are owned by the corresponding row from the locked table. |
Grid popup editor
The popup editor consists of a Window component containing a Form component.
Window accessibility specification
Form accessibility specification
Grid footer
The Aggregates totals are placed within a <tfoot>
element in the Content <table>
.
Selector | Attribute | Usage |
---|---|---|
tfoot | role=rowgroup | Required as the owner <table> element has its semantic role removed. |
tfoot>tr | role=row | Required as the owner <table> element has its semantic role removed. |
aria-rowindex | Row number including all headers, data (including master and detail) rows, and footers starting from 1. Footer rows are always the last ones in a Grid. Needed only when Paging (and more that 1 page is present in the component), Virtual rows, or Master/Detail rows (Hierarchical Grid, Detail Template Grid) are enabled. If data is also Grouped, the proper indexing could not be calculated. Hence, the attribute must not be set. | |
tfoot>tr>td | role=gridcell | Required as the owner <table> element has its semantic role removed. |
aria-colindex | Col number, based on leaf columns, starting from 1. Needed only for Virtual columns and Hidden columns scenarios, when not all columns are rendered in the DOM. Otherwise, can be interpreted from the DOM structure. Can be calculated by summing previous columns colspans. |
Pager
For the Grid Pager WAI-ARIA spec, please review the Pager component.
Pager accessibility specification
Grid selection aggregates
The selection aggregates are placed within a .k-grid-selection-aggregates
element after the Grid .k-grid-aria-root
element.
Selector | Attribute | Usage |
---|---|---|
.k-grid-selection-aggregates | aria-live=polite | Ensures that changes in the calculated selection aggregates are announced by assistive technologies. |
Data Grid Stacked Layout
The element is a regular Grid cell (td element) that holds a stacked layout content representing all available column headers and content for the given row. All internal "stacked cell" elements become focusable when focus is moved within the cell.
Selector | Attribute | Usage |
---|---|---|
.k-grid-stack-cell | tabindex=0 | "Stacked cell" elements receive tabindex '0' when focus is within their parent '.k-grid-stack-row' element. This allows the end user to navigate through the content using Tab. The tabindex attribute is removed when focus leaves the '.k-grid-stack-row' element. |
Resources
WAI-ARIA specification for grid
Section 508
The Grid is fully compliant with the Section 508 requirements.
Testing
The Grid has been extensively tested automatically with axe-core and manually with the most popular screen readers.
To report any accessibility issues, contact the team through the Telerik Support System.
Screen Readers
The Grid has been tested with the following screen readers and browsers combinations:
Environment | Tool |
---|---|
Firefox | NVDA |
Chrome | JAWS |
Microsoft Edge | JAWS |
Keyboard Navigation
For more details on how the Grid keyboard navigation works, refer to the Keyboard Navigation article.