Accessibility in EJ2 TypeScript Grid control

28 May 202424 minutes to read

The Grid control followed the accessibility guidelines and standards, including ADA, Section 508, WCAG 2.2 standards, and WCAG roles that are commonly used to evaluate accessibility.

The accessibility compliance for the Grid control is outlined below.

Accessibility Criteria Compatibility
WCAG 2.2 Support Intermediate
Section 508 Support Intermediate
Screen Reader Support Yes
Right-To-Left Support Yes
Color Contrast Yes
Mobile Device Support Yes
Keyboard Navigation Support Intermediate
Accessibility Checker Validation Intermediate
Axe-core Accessibility Validation Intermediate
Yes - All features of the control meet the requirement.
Intermediate - Some features of the control do not meet the requirement.
No - The control does not meet the requirement.

WAI-ARIA attributes

The Grid control followed the WAI-ARIA patterns to meet the accessibility. The following ARIA attributes are used in the Grid control:

Attributes Purpose
role=grid To represent the element containing the grid control.
role=row To represent the element containing the cells of the row in the grid.
role=rowgroup To represent the group of rows in the grid.
role=columnheader To represent the cell in a row contains header information for a column in the grid.
role=gridcell To represent a cell in the grid control.
role=button To represent the element that acts as a button in the grid.
role=search To represent the element that acts as a search region in the grid.
role=presentation To represent the element to be not available for accessibility concerns.
role=navigation To represent the element containing pager elements to navigate from one page to another.
aria-colindex Defines the column index of the column with respect to the total number of columns within the grid.
aria-rowindex Defines row index of the row with respect to the total number of rows within the grid.
aria-rowspan Defines the number of rows spanned by a cell within the grid.
aria-colspan Defines the number of columns spanned by a cell within the grid.
aria-rowcount Defines the total number of rows in the grid.
aria-colcount Defines the total number of columns in the grid.
aria-selected Indicates the current “selected” state of the rows and cells in the grid.
aria-expanded Indicate if the expand icon in the hierarchy grid or grouped grid or detail grid is expanded or collapsed
aria-sort Indicates whether the data in the grid are sorted in ascending or descending order.
aria-busy Indicates an element is being modified and that assistive technologies may want to wait until the changes are complete before informing the user about the update.
aria-owns Identifies an element in order to define a visual, functional, or contextual relationship between a parent and its child elements.
aria-hidden Hides the element from accessibility concerns.
aria-labelledby Provides an accessible name for the checkbox labels in excel filter, checkbox filter and column chooser dialog.
aria-describedby Provides an description about the features enabled in the header when the grid header cell is focused.

The Syncfusion Grid control is structured with a two-table architecture for its header and content. To enhance accessibility for screen readers, roles and ARIA attributes are incorporated for both the grid parent and all its child elements. Although this architectural approach may have some limitations with accessibility checker tools. It’s important to note that these limitations do not affect the readability of the grid content over screen readers.

The accessibility checker tools highlights the following known issues:

  • aria-required-children: This warning appears when rendering the grid without any features, as it contains textarea and grid content. Additionally, it appears when enabling features such as the toolbar and grouping.

  • color-contrast: This warning appears when you are enabling the search item in the grid’s toolbar.

  • An explicit ARIA ‘role’ is not valid for <tr> element within an ARIA role ‘grid’ per the ARIA in HTML specification.

  • An explicit ARIA ‘role’ is not valid for <th> element within an ARIA role ‘grid’ per the ARIA in HTML specification.

  • An explicit ARIA ‘role’ is not valid for <td> element within an ARIA role ‘grid’ per the ARIA in HTML specification.

  • The element with role “button” contains descendants with roles “rowgroup” which are ignored by browsers.

  • Content is not within a landmark element.

  • Multiple elements with “search” role do not have unique labels.

  • Text contrast of 4.10 with its background is less than the WCAG AA minimum requirements for text of size 13px and weight of 400.

  • Interactive control with ARIA role ‘grid’ does not have a programmatically associated name.

  • The element with role “rowgroup” is not contained in or owned by an element with one of the following roles: “grid, table, treegrid”.

Keyboard interaction

The Grid control followed the keyboard interaction guideline, making it easy for people who use assistive technologies (AT) and those who completely rely on keyboard navigation. The following keyboard shortcuts are supported by the Grid control.

Pager

Windows MAC To do this
Tab Tab Focus on the next pager item.
Shift + Tab Shift + Tab Focus on the previous pager item.
Enter / Space Enter / Space Select the currently focused page.
PageUp / Left Arrow Left Arrow Navigate to previous page.
PageDown / Right Arrow Right Arrow Navigate to next page.
Home / Ctrl + Alt + PageUp Fn + Left Arrow Navigate to first page.
End / Ctrl + Alt + PageDown Fn + Right Arrow Navigate to last page.

Focus Elements

Windows MAC To do this
Home Fn + Left Arrow Moves the focus to the first cell of the focused row.
End Fn + Right Arrow Moves the focus to the last cell of the focused row.
Ctrl + Home Command + Fn + Left Arrow Moves the focus to the first Cell of the first row in the grid.
Ctrl + End Command + Fn + Right Arrow Moves the focus to the last Cell of the last row in the grid.
Up Arrow Up Arrow Moves the cell focus upward from the focused cell.
Down Arrow Down Arrow Moves the cell focus downward from the focused cell.
Right Arrow Right Arrow Moves the cell focus right side from the focused cell.
Left Arrow Left Arrow Moves the cell focus left side from the focused cell.
Alt + J Alt + J Moves the focus to the entire grid.
Alt + W Alt + W Move the focus to the grid content element.

Selection

Windows MAC To do this
Up Arrow Up Arrow Moves up a row/cell selection from the selected row/cell.
Down Arrow Down Arrow Moves down a row/cell selection from the selected row/cell.
Right Arrow Right Arrow Moves to the right cell selection from the selected cell.
Left Arrow Left Arrow Moves to the left cell selection from the selected cell.
Shift + Up Arrow Shift + Up Arrow Extends the row/cell selection upwards from the selected row/cell.
Shift + Down Arrow Shift + Down Arrow Extends the row/cell selection downwards from the selected row/cell.
Shift + Right Arrow Shift + Right Arrow Extends the cell selection to the right side from the selected cell.
Shift + Left Arrow Shift + Left Arrow Extends the cell selection to the left side from the selected cell.
Enter Enter Moves the row/cell selection downward from the selected cell/row.
Shift + Enter Shift + Enter Moves the row/cell selection upward.
Esc Esc Deselects all the selected row/cells.
Ctrl + A Ctrl + A Select all the row/cells in the current page.

Grouping

Windows MAC To do this
Ctrl + Up Arrow Command + Up Arrow Collapses all the visible groups.
Ctrl + Down Arrow Command + Down Arrow Expands all the visible groups.
Ctrl + Space Ctrl + Space Performs grouping when focused on a header element.
Enter Enter If the current cell is an expand/collapse cell then expands/collapses the current group/detailrow/childgrid.

Print

Windows MAC To do this
Ctrl + P Command + P Prints the Grid.

Clipboard

Windows MAC To do this
Ctrl + C Command + C Copies selected rows or cells data into the clipboard.
Ctrl + Shift + H Ctrl + Shift + H Copies selected rows or cells data with header into clipboard

Editing

Windows MAC To do this
F2 F2 Starts editing of selected row if Mode is Normal/Dialog or Starts editing of selected cell if Mode is Batch.
Enter Enter Saves the current form it the Mode is Normal or Dialog / Saves the current cell and starts editing the next row cell if Mode is Batch.
Insert Ctrl + Command + Enter Creates a new add form depending on the NewRowPosition.
Delete Delete Deletes the current selected record.
Tab Tab Navigates to the next editable cell if the Mode is Normal or Dialog / Saves the current cell and starts editing the next cell is Mode is Batch.
Shift + Tab Shift + Tab Navigates to the previous editable cell if the Mode is Normal or Dialog / Saves the current cell and starts editing the previous cell is Mode is Batch.
Shift + Enter Shift + Enter Saves the current cell and starts editing the previous row cell if Mode is Batch.

Filtering

Windows MAC To do this
Alt + Down arrow Alt + Down arrow Opens the filter menu(excel, menu and checkbox filter) when its header element is in focused state.

Column Menu

Windows MAC To do this
Alt + Down arrow Alt + Down arrow Opens column menu when its header element is in focused state.

Reordering

Windows MAC To do this
Ctrl + left arrow or right arrow Command + left arrow or right arrow Reorders the focused header column to the left or right side.

Sorting

Windows MAC To do this
Enter Enter Performs sorting(ascending/descending) on a column when its header element is in focused state.
Ctrl + Enter Command + Enter Performs multi-sorting on a column when its header element is in focused state.
Shift + Enter Shift + Enter Clears sorting for the focused header column.


  • The Command and Control keys on Mac devices can be interchanged. When this switch occurs, use the Command key in place of the Control key and the Control key in place of the Command key for the above listed key interactions with Mac devices. For example, after switching the keys to group the columns when the header element is focused use Command + Space and for expanding the visible groups use Ctrl + Down Arrow.

How to prevent default key action behavior

The Syncfusion EJ2 TypeScript Grid provides flexibility to prevent the default key action behavior based on your requirements. This enables you to intercept and customize the behavior when specific keys are pressed within a web application

To prevent the default key action behavior in the grid, you can utilize the keyPressed event. This event is triggered for every key press, allowing you to customize the behavior based on the pressed key.

The following example demonstrates how to prevent the default behavior of the “ENTER” key using the keyPressed event.

import { Grid, KeyboardEventArgs } from '@syncfusion/ej2-grids';
import { data } from './datasource.ts';

let grid: Grid = new Grid({
    dataSource: data,
    keyPressed:keyPressed,
    columns: [
        { field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120 },
        { field: 'CustomerID', headerText: 'Customer ID', width: 150 },
        { field: 'ShipCity', headerText: 'Ship City', width: 150 },
        { field: 'ShipName', headerText: 'Ship Name', width: 150 },
    ],
    height: 315
});
grid.appendTo('#Grid');

function keyPressed(args: KeyboardEventArgs)
{
    if (args.keyCode === 13) {
        // Prevent the default Enter key action
        args.cancel = true;
      }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>EJ2 Grid</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript Grid Control" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-base/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-grids/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-buttons/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-popups/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-navigations/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-lists/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-inputs/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-calendars/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body>
    <div id='loader'>Loading....</div>
    <div id='container'>
        <div id='Grid'></div>
    </div>
</body>
</html>

Custom shortcut keys to perform grid actions

The Syncfusion EJ2 TypeScript Grid control enables you to enhance the usablity of keyboard shortcuts for various grid actions and navigation. In addition to the built-in keyboard navigation capabilities, you can implement custom keyboard shortcuts to execute specific actions.

To achieve this, you can utilize the keyPressed event of the grid. This event is triggered for every key press, allowing you to customize the behavior based on the pressed key.

The following example demonstrates how to perform grid actions using shortcut keys through the keyPressed event. Within the event, define the following custom shortcuts to perform various grid actions:

  • Pressing N adds a new record.
  • Pressing Ctrl + S save a record by invoking endEdit.
  • Pressing Ctrl + D deletes a record.
  • Pressing Ctrl + A selects all rows.
  • Pressing Ctrl + G groups the grid by a specified column.

And prevented the default actions associated with the following keyboard shortcuts used for default grouping and editing action:

  • Ctrl + Space
  • Insert
  • F2
  • Delete
  • Enter

You can add more custom shortcuts and actions as needed to enhance the functionality of your Syncfusion EJ2 TypeScript Grid control.

import { Grid, Group, Edit, Selection, Toolbar, KeyboardEventArgs } from '@syncfusion/ej2-grids';
import { data } from './datasource.ts';

Grid.Inject(Group, Edit, Selection, Toolbar);

let grid: Grid = new Grid({
    dataSource: data,
    editSettings:{ allowEditing: true, allowAdding: true, allowDeleting: true },
    toolbar:['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
    selectionSettings:{type: 'Multiple'},
    allowGrouping: true,
    keyPressed:keyPressed,
    columns: [
        { field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', isPrimaryKey:true, width: 120 },
        { field: 'CustomerID', headerText: 'Customer ID', width: 120 },
        { field: 'ShipCountry', headerText: 'Ship Country', width: 150 }
    ],
    height: 315
});
grid.appendTo('#Grid');

function keyPressed(e: KeyboardEventArgs)
{
    var key = e.key.toLowerCase();
    switch (key) {
        case 'n':
            e.preventDefault();
            grid.addRecord();
            break;
        case 's':
            if (e.ctrlKey) {
                e.preventDefault();
                grid.endEdit();
            }
            break;
        case 'd':
            if (e.ctrlKey) {
                e.preventDefault();
                grid.deleteRecord();
            }
            break;
        case 'a':
            if (e.ctrlKey) {
                e.preventDefault();
                grid.selectRowsByRange(0);
            }
            break;
        case 'g':
            if (e.ctrlKey) {
                e.preventDefault();
                grid.groupColumn('CustomerID');
            }
            break;
        case 'enter':
            e.preventDefault();
            e.cancel = true;
            grid.refreshColumns();
            break;
        case 'insert':
            e.preventDefault();
            e.cancel = true;
            break;
        case 'delete':
            e.preventDefault();
            e.cancel = true;
            break;
        case 'f2':
            e.preventDefault();
            e.cancel = true;
            break;
        case '" "':
            if (e.ctrlKey) {
                e.preventDefault();
                e.cancel = true;
            }
            break;
        // Add more custom shortcuts as needed
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>EJ2 Grid</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript Grid Control" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-base/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-grids/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-buttons/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-popups/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-navigations/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-lists/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-inputs/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-calendars/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body>
    <div id='loader'>Loading....</div>
    <div id='container'>
        <div id='Grid'></div>
    </div>
</body>
</html>

Ensuring accessibility

The Grid control’s accessibility levels are ensured through an accessibility-checker and axe-core software tools during automated testing.

The accessibility compliance of the Grid control is shown in the following sample. Open the sample in a new window to evaluate the accessibility of the Grid control with accessibility tools.

import { Grid, Group, Filter, Page, Sort, Selection, Toolbar, Edit, Aggregate, RowDD } from '@syncfusion/ej2-grids';
import { data } from './datasource.ts';

Grid.Inject(Group, Filter, Page, Sort, Selection, Toolbar, Edit, Aggregate, RowDD);

let grid: Grid = new Grid({
    dataSource: data,
    toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search', 'ColumnChooser'],
    searchSettings: { fields: ['ShipCountry'], operator: 'contains', key: 'a', ignoreCase: true },
    allowPaging: true,
    allowReordering: true,
    allowRowDragAndDrop: true,
    pageSettings: { pageCount: 2, pageSizes: true },
    allowGrouping: true,
    selectionSettings: { type: 'Multiple', mode: 'Both' },
    selectedRowIndex: 6,
    allowSorting: true,
    sortSettings: { columns: [{ field: 'OrderID', direction: 'Ascending' }, { field: 'ShipCity', direction: 'Descending' }] },
    allowFiltering: true,
    filterSettings: { type: 'Excel' },
    editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' },
    groupSettings: { columns: ['CustomerID'] },
    showColumnChooser: true,
    columns: [
        { type: 'checkbox', width: 50 },
        { field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120 },
        { field: 'CustomerID', headerText: 'Customer ID', width: 150 },
        { field: 'OrderDate', headerText: 'Order Date', textAlign: 'Right', width: 135, format: 'yMd' },
        { field: 'Freight', headerText: 'Freight($)', textAlign: 'Right', width: 120, format: 'C2' },
        { field: 'ShipCity', headerText: 'Ship City', width: 150 },
        { field: 'ShipCountry', headerText: 'Ship Country', width: 140 },
        { field: 'ShipName', headerText: 'Shipped Name', textAlign: 'Right', width: 145 },
    ],
    aggregates: [{
        columns: [{
            type: 'Sum',
            field: 'Freight',
            format: 'C2',
            groupFooterTemplate: 'Sum: ${Sum}'
        }]
    },
    {
        columns: [{
            type: 'Sum',
            field: 'Freight',
            format: 'C2',
            footerTemplate: 'Sum: ${Sum}'
        }]
    },
    {
        columns: [{
            type: 'Max',
            field: 'Freight',
            groupCaptionTemplate: 'Max: ${Max}'
        }]
    }],
});

grid.appendTo('#Grid');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 Grid</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Typescript Grid Control" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-base/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-grids/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-buttons/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-popups/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-richtexteditor/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-navigations/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-lists/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-inputs/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-calendars/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-notifications/styles/bootstrap5.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/27.2.2/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet" />

    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        .e-row[aria-selected="true"] .e-customizedExpandcell {
            background-color: #e0e0e0;
        }
        .e-grid.e-gridhover tr[role='row']:hover {
            background-color: #eee;
        }
        .e-expand::before {
        content: '\e5b8';
    }
    .empImage {
        margin: 6px 16px;
        float: left;
        width: 50px;
        height: 50px;
    }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body>
    <div id='loader'>Loading....</div>
    <div id='container'>
        <div id='Grid'></div>
    </div>
</body>
</html>

See also