A TableView
displays a list of content with rows and columns.
It supports many advanced features like sorting, infinite scrolling, drag and drop both into and out of the table,
multiple selection, keyboard navigation, and more. It is designed to scale to collections of any size using a virtual scroller
that only renders the currently visible items into the DOM.
The TableView
component implements the Data Grid design pattern, per WAI-ARIA Authoring Practices 1.2.
A grid
can be used to present tabular information that has column titles, row titles, or both.
The grid
pattern is particularly useful if the tabular information is editable or interactive.
For example, when data elements are links to more information, rather than presenting them in a static table and including the links in the tab sequence,
implementing the grid
pattern provides users with intuitive and efficient keyboard navigation of the grid
contents as well as a shorter tab sequence for the page.
A grid
may also offer functions, such as cell content editing, selection, cut, copy, and paste.
In a grid
, every cell contains a focusable element or is itself focusable, regardless of whether the cell content is editable or interactive.
There is one exception: if column or row header cells do not provide functions, such as sort or filter, they do not need to be focusable.
One reason it is important for all cells to be able to receive or contain keyboard focus is that screen readers will typically be in their application reading mode, rather than their document reading mode, when users are interacting with the grid.
While in application mode, a screen reader user hears only focusable elements and content that labels focusable elements.
So, screen reader users may unknowingly overlook elements contained in a grid that are either not focusable or not used to label a column or row.
The following keys provide grid navigation by moving focus among rows and cells of the grid. Implementations of grid make these key commands available when an element in the grid has received focus, e.g., after a user has moved focus to the grid using the Tab key.
ArrowDown
- With focus on a row within the grid, moves focus to the next row within the grid.
- With focus on a cell within a row, moves focus to the cell in the same column of the next row.
ArrowUp
- With focus on a row within the grid, moves focus to the previous row within the grid.
- With focus on a cell within a row, moves focus to the cell in the same column of the previous row.
ArrowRight
- With focus on a row within the grid, moves focus to the first cell within the row.
- With focus on or within a cell within a row, moves focus to the next cell within the row.
- With focus on or within the right-most cell in the row, focus does not move.
ArrowLeft
- With focus on or within a cell within a row, moves focus to the previous cell within the row.
- With focus on or within the left-most cell in the row, focus should move to the parent row.
- With focus on a row within the grid, focus does not move.
PageDown
- Moves focus down a number of rows, typically scrolling so the bottom row in the currently visible set of rows becomes one of the first visible rows.
- With focus on a cell within a row, focus should move to the cell in the same column of the row that receives focus after scrolling.
- With focus on or within the last row of the grid, focus does not move.
PageUp
- Moves focus up a number of rows, typically scrolling so the top row in the currently visible set of rows becomes one of the last visible rows.
- With focus on a cell within a row, focus should move to the cell in the same column of the row that receives focus after scrolling.
- With focus on or within the first row of the grid, focus does not move.
Home
- With focus on a row within the grid, moves focus to the first row in the dataset for the grid, scrolling it into view.
- With focus on a cell within a row, moves focus to the first cell in the row that contains focus.
End
- With focus on a row within the grid, moves focus to the last row in the dataset for the grid, scrolling it into view.
- With focus on a cell within a row, moves focus to the last cell in the row that contains focus.
Control/Command + Home
- With focus on a row within the grid, moves focus to the first row in the dataset for the grid, scrolling it into view.
- With focus on a cell within a row, moves focus to the first cell in the first row in the dataset for the grid, scrolling it into view.
Control/Command + End
- With focus on a row within the grid, moves focus to the last row in the dataset for the grid, scrolling it into view.
- With focus on a cell within a row, moves focus to the last cell in the last row in the dataset for the grid, scrolling it into view.
When a row or any of its decendants has focus, any interactive control within the row, such as a link, checkbox, switch or button, should made tabbable using tabIndex={0}
.
Interactive controls within rows that do not contain focus should be removed from the document tab order using tabIndex={-1}
.
If a grid supports selection of rows, Spectrum does not currently support column or cell selection, the following keys are used for these functions:
- With focus on a row or cell,
Space
toggles selection of the row.Shift + ArrowDown
extends selection one row down.Shift + ArrowUp
extends selection one row up.Shift + PageDown
extends selection one page down.Shift + PageUp
extends selection one page up.Control/Command + A
- selects all rows in the dataset.
- (optional) depending on the size of the dataset, displays a dialog offering the user the option to select only visible rows, or all rows in the dataset.
Escape
(optional) deselects all selected rows.Control/Command + C
(optional) depending on context, copies selected rows to the clipboard.Control/Command + V
(optional) depending on context, pastes rows from the clipboard into the table.
This section describes two important aspects of keyboard interaction design for data grid patterns:
- Choosing whether a cell or an element inside a cell receives focus in response to grid navigation key events.
- Enabling grid navigation keys to be used to interact with elements inside of a cell.
For assistive technology users, the quality of experience when navigating a grid heavily depends on both what a cell contains and on where keyboard focus is set. For example, if a cell contains a button and a grid navigation key places focus on the cell instead of the button, screen readers announce the button label but do not tell users a button is present.
There are two optimal cell design and focus behavior combinations:
- A cell contains one widget whose operation does not require arrow keys and grid navigation keys set focus on that widget. Examples of such widgets include link, button, menubutton, toggle button, radio button (not radio group), switch, and checkbox.
- A cell contains text or a single graphic and grid navigation keys set focus on the cell.
While any combination of widgets, text, and graphics may be included in a single cell, grids that do not follow one of these two cell design and focus movement patterns add complexity for authors or users or both.
While navigation keys, such as arrow keys, are moving focus from cell to cell, they are not available to perform actions like operate a combobox or move an editing caret inside of a cell. The user may need keys that are used for grid navigation to operate elements inside a cell if a cell contains:
- Editable content.
- Multiple widgets.
- A widget that utilizes arrow keys in its interaction model, such as a radio group or slider.
Use the following keyboard conventions for disabling and restoring grid navigation functions.
Enter
: Disables grid navigation and:- If the cell contains editable content, places focus in an input field, such as a textbox. If the input is a single-line text field, a subsequent press of Enter may either restore grid navigation functions or move focus to an input field in a neighboring cell.
- If the cell contains one or more widgets, places focus on the first widget.
Alphanumeric keys
: If the cell contains editable content, places focus in an input field, such as a textbox.
When grid navigation is disabled, conventional changes to navigation behaviors include:
Escape
: restores grid navigation. If content was being edited, it may also undo edits.ArrowRight
orArrowDown
: If the cell contains multiple widgets, as with a radiogroup, moves focus to the next widget inside the cell, optionally wrapping to the first widget if focus is on the last widget. Otherwise, passes the key event to the focused widget.ArrowLeft
orArrowUp
: If the cell contains multiple widgets, as with a radiogroup, moves focus to the previous widget inside the cell, optionally wrapping to the first widget if focus is on the last widget. Otherwise, passes the key event to the focused widget.Tab
: moves focus to the next widget in the grid. Optionally, the focus movement may wrap inside a single cell or within the grid itself.Shift + Tab
: moves focus to the previous widget in the grid. Optionally, the focus movement may wrap inside a single cell or within the grid itself.
- The table container has the role of
grid
. - Each row container has role of
row
and is either a DOM descendant of or owned by thegrid
element or an element with role ofrowgroup
.- The header row or rows should be contained within an element with the role of
rowgroup
. - The scrolling table body element should be have the role of
rowgroup
. - Any other container element used to control layout, like for example the container elements that position item views within a virtual scroller, should have the role of
presentation
.
- The header row or rows should be contained within an element with the role of
- Each cell is either a DOM descendant of, or owned by, a
row
element and has one of the following roles:columnheader
if the cell contains a title or header information for the column.rowheader
if the cell contains title or header information for the row.gridcell
if the cell does not contain column or row header information.
- If there is an element in the user interface that serves as a label for the
grid
,aria-labelledby
is set on thegrid
element with a value that refers to the labelling element. Otherwise, a label is specified for thegrid
element usingaria-label
. - If the grid has a description,
aria-describedby
is set on the grid element with a value referring to the element containing the description. - If the grid provides sort functions,
aria-sort
is set to an appropriate value on the header cell element for the sorted column or row as described in the section on grid and table properties. - Grid navigation using the arrow keys, page up/down, home or end focuses the
row
element. To improve announcement when it receives focus, eachrow
should be labelled by column headers, and cells that best describe therow
usingaria-labelledby
.TableView
should provide an API to specify which columns to include in thearia-labelledby
for a row.
- If the grid supports selection, when a cell or row is selected, the selected element has
aria-selected
settrue
.- The checkbox in the header row for selecting all items in the collection should have
aria-label
set to the localized string "Select All"." - The checkbox for selection of an item row should have
aria-label
set to a localized string that expresses the current selected state for the row, either "Selected" or "Select". - The checkbox in the first cell of an item row should also include an
aria-labelledby
prop that references the same columns used to label the parentrow
followed by the checkbox itself, to provide a clear indication of the selected state for the row. - When selected, the
aria-labelledby
attribute for the row should be updated to include a reference to the checkbox to ensure that the selected state for arow
will be announced by a screen reader when therow
receives focus.
- The checkbox in the header row for selecting all items in the collection should have
- If the grid provides content editing functionality and contains cells that may have edit capabilities disabled in certain conditions,
aria-readonly
may be settrue
on cells where editing is disabled. If edit functions are disabled for all cells,aria-readonly
may be settrue
on thegrid
element. Grids that do not provide editing functions do not include thearia-readonly
attribute on any of their elements. - If there are conditions where some rows or columns are hidden or not present in the DOM, e.g., data is dynamically loaded when scrolling or the grid provides functions for hiding rows or columns, the following properties are applied as described in the section on grid and table properties.
aria-colcount
oraria-rowcount
is set to the total number of columns or rows, respectively.aria-rowcount
oraria-colcount
must update whenever items are added or removed from the dataset, or whenever a column is added or removed from the dataset.aria-colindex
oraria-rowindex
is set to the position of a cell within a row or column, respectively.
- If the grid includes cells that span multiple rows or multiple columns, and if the
grid
role is NOT applied to an HTMLtable
element, thenaria-rowspan
oraria-colspan
is applied as described in grid and table properties.
- If the element with the
grid
role is an HTMLtable
element, then it is not necessary to use ARIA roles for rows and cells because the HTML elements have implied ARIA semantics. For example, an HTML<TR>
has an implied ARIA role ofrow
. A grid built from an HTMLtable
that includes cells that span multiple rows or columns must use HTMLrowspan
andcolspan
and must not usearia-rowspan
oraria-colspan
. - If rows or cells are included in a grid via
aria-owns
, they will be presented to assistive technologies after the DOM descendants of thegrid
element unless the DOM descendants are also included in thearia-owns
attribute.
There are several important considerations when a table uses virtual scrolling to enable fast scrolling of large datasets.
- After scrolling, the order of visible item views in the DOM must match the order of item views in the dataset.
- While scrolling, if the
focusedKey
has scrolled out of view so that it is no longer rendered, focus should be set to the container element for the virtual scroller itself, so that focus is not lost to thedocument.body
and the virtual scroller will continue to handle grid navigation keys. - If the
focusedKey
is scrolled out of view, when the user navigates away from the grid, the grid should be made tabbable by settingtabIndex={0}
. When keyboard navigation restores focus to the grid, the grid should marshall focus to thefocusedKey
and scroll the item into view. - When navigating using a screen reader, using browse mode in particular, there is now way for force the loading of additional item views when the last, or first item, in the virtual scroller has been read. For this use case, it may become necessary to include a screen-reader only row, spanning all columns, before and after of the visible item views in the DOM that contain a button that allows a screen reader to load more items.