Accessibility

Jspreadsheet renders real DOM elements and exposes the ARIA grid model, so assistive technology reads the data grid as a grid of rows and cells, and every interaction is available from the keyboard. This page collects what the data grid does for accessibility and where the related settings are documented.

What's new with Version 13

  • ARIA grid model: gridcell, rows with aria-rowindex, column headers with aria-colindex, row headers, aria-rowcount and aria-colcount on the virtualized grid, aria-sort on sorted headers and aria-selected on the cursor cell
  • Keyboard: Ctrl + Arrow follows the Excel block contract, Ctrl + D and Ctrl + R fill, and the keyboard navigation recovers when the browser window regains focus
  • Context menu: opens from the keyboard with Shift + F10 or the context menu key, and can be navigated with the arrows

Documentation

ARIA model

Attribute or role Where Description
role="grid" The table The data grid is announced as a grid.
aria-rowcount, aria-colcount The table The full dimensions of the worksheet, even though only the visible cells are rendered.
role="row", aria-rowindex Each rendered row The one-based position of the row in the worksheet.
role="columnheader", aria-colindex Each column header The one-based position of the column.
role="rowheader" The row number cell The header of the row.
role="gridcell" Each cell A cell of the grid.
aria-selected="true" The cursor cell The cell that receives the keyboard input.
aria-sort A sorted column header ascending or descending; every level of a multi column sort carries its own value.

Keyboard

The whole data grid is operable from the keyboard: cell navigation, block jumps, selection, editing, copy, cut and paste, fill, undo and redo, the context menu, the filters, the worksheets and the top menu. The complete list is in the shortcuts section, and custom shortcuts can be registered through jspreadsheet.shortcuts.set.

Area Keys
Navigation Arrows, Tab, Enter, Page Up, Page Down, Ctrl + Arrow for the Excel block jumps
Selection Shift + Arrow, Ctrl + Shift + Arrow, Ctrl + A
Editing F2, typing to start, Enter and Tab to confirm, Esc to cancel, Delete to clear
Fill Ctrl + D, Ctrl + R
Clipboard Ctrl + C, Ctrl + X, Ctrl + V
History Ctrl + Z, Ctrl + Y
Context menu Shift + F10, the context menu key
Filters Alt + Arrow Down opens the filter of the current column
Worksheets Alt + Arrow Left, Alt + Arrow Right, Shift + F11
Top menu Alt focuses the menu bar when present

Editors

The native editors support IME composition for languages that need it, and the dropdown, autocomplete and calendar widgets are navigable with the keyboard. Custom editors keep the same contract: an editor implemented as a web component receives the keyboard events of the cell. See the editors section.

Colour and contrast

The visual state of the grid is carried by CSS variables, so a theme can raise the contrast of the selection, the headers and the gridlines without touching the markup. The header of a fully selected column or row carries the jss_full class in addition to selected, and the row group outline emits jss_group_header and jss_group_level_1 to jss_group_level_8, so every state has a hook for a high contrast theme. See the themes section.

Settings that affect accessibility

Setting Description
moveDownOnEnter: boolean Move the cursor down on Enter. Default: true.
allowManualInsertRow, allowManualInsertColumn Create a new row or column with Enter or Tab on the last one.
columnSortingOnDblClick: boolean Sort from the header with a double click, or Shift + double click to add a level.
keyboardFormulas: boolean Enable the formula picker from the keyboard. Default: true.
contextMenu The context menu items can be customized; the menu stays keyboard operable.

Example

The example reads the ARIA attributes of the cursor cell after each move, which is what a screen reader announces.

<html>
<script src="https://jspreadsheet.com/v13/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v13/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<div id="spreadsheet"></div>

<p id="status" aria-live="polite"></p>

<script>
// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('MTVhYThjNjY3ODk0MWYwM2I1ZDc3ZDhkY2RlNTU1Nzg3YTAyNGJhOWFkZmZlODBkYTk3NGFkMTEyMzhkZGJiNzRhMTQ1M2VjYmU3MjQ3Njc2NWIyODVkZjI0YWUwMWUxMGM1ZDFmMjRjYjZkZTNlZDZhZTAwNzgzNDYzZjgxNzcsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpnNE9ESTNORFU1TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// Create the spreadsheet
let worksheets = jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [{
        data: [
            ['Product', 'Quantity', 'Price'],
            ['Apples', 12, 1.2],
            ['Pears', 7, 1.6],
            ['Grapes', 3, 4.1],
        ],
        columns: [
            { title: 'Product', width: 140 },
            { title: 'Quantity', width: 100, type: 'number' },
            { title: 'Price', width: 100, type: 'number' },
        ],
    }],
    onselection: function(worksheet, x1, y1) {
        let cell = worksheet.getCellFromCoords(x1, y1);
        let row = cell.parentNode;
        document.getElementById('status').textContent =
            'Row ' + row.getAttribute('aria-rowindex') +
            ', column ' + (x1 + 1) +
            ', role ' + cell.getAttribute('role') +
            ', selected ' + cell.getAttribute('aria-selected');
    },
});
</script>
</html>

See Also