Add keyboard navigation
Use this guide when users need to move through dense tables quickly without relying on the mouse.
Row states
Keyboard navigation in react-datatable is built around an active row.
The active row is where keyboard movement currently is; selection is which rows are included in bulk actions.
Show one table state with an active row, selected rows, and an open preview so the differences are visible at a glance.
Use keyboard navigation when users need to:
- move row by row with
ArrowUpandArrowDown - open the active row with
Enter - toggle preview with
Space - expand or collapse grouped headers from the keyboard
If the table only needs checkbox selection and occasional mouse clicks, you may not need this yet.
Enable keyboard navigation explicitly
Turn it on with the keyboardNavigation prop.
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
keyboardNavigation={{
enabled: true,
autoFocus: true,
}}
/>autoFocus defaults to true when keyboard navigation is active, so only disable it when another control should keep initial focus.
[!NOTE] Screenshot placeholder: active row, open-row action, and preview toggle visible in a realistic table with grouped and ungrouped states.
Supported keyboard navigation
react-datatable already supports these keyboard behaviors:
ArrowUpandArrowDownmove the active rowEnteropens the active data row throughrowActions.onOpenRowSpacetoggles preview when preview is configuredEnterandSpacetoggle grouped headers when the active item is a group headerEsccloses preview before clearing other interaction state
Use rowActions.onOpenRow for the main keyboard open behavior.
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
keyboardNavigation={{ enabled: true }}
rowActions={{
onOpenRow: ({ row, rowId, trigger }) => {
openCustomer(rowId, { trigger })
},
}}
/>When Enter fires on an active data row, the table calls onOpenRow with trigger: "keyboard".
That makes it easy to share one row-opening path across mouse and keyboard flows while still preserving analytics or UI branching when needed.
Wire Space to row preview when preview is available
Use preview when users need quick inspection without fully opening the row.
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
keyboardNavigation={{ enabled: true }}
rowActions={{
onTogglePreviewRow: ({ rowId, nextOpen }) => {
trackPreviewToggle(rowId, nextOpen)
},
}}
preview={{
floating: {
draggable: true,
storageKey: "customers-preview",
},
renderPreview: ({ row, close }) => <CustomerPreview customer={row} onClose={close} />,
}}
/>When preview is configured:
Spacetoggles preview for the active data rowEsccloses the preview first- the row action callback can observe whether the preview is opening or closing
The grid also enables keyboard navigation by default when preview rendering or onOpenRow is present, but it is still better to configure the behavior intentionally.
[!NOTE] Screenshot placeholder: active row with keyboard focus ring plus an open preview panel, showing the keyboard-driven inspection loop rather than only the resting table state.
Grouped rows change Enter and Space behavior
Grouped headers are keyboard-active items too.
When the active item is a group header instead of a data row:
Entertoggles group expansionSpacealso toggles group expansion
That means grouped tables need a clear mental model:
- data rows open or preview
- group headers expand or collapse
If you mix grouping and keyboard navigation, test both grouped and ungrouped states instead of assuming row behavior carries over unchanged.
Be deliberate about focus ownership
The grid can claim focus on mount when keyboard navigation is enabled.
Keep autoFocus enabled when the table is the main work surface.
Disable it when:
- the page opens into a search field or form
- the table appears below a required input
- automatic grid focus would interrupt a setup flow
<Datatable
tableKey="customers"
data={rows}
columns={columns}
getRowId={(row) => row.id}
keyboardNavigation={{
enabled: true,
autoFocus: false,
}}
/>A table that steals focus at the wrong moment feels broken even when the keyboard logic itself is correct.
[!NOTE] Screenshot placeholder: a page layout where the table is below another input, illustrating when
autoFocus: falseprotects the surrounding setup flow.
Verify keyboard navigation before you move on
Before you continue, confirm that:
ArrowUpandArrowDownmove the active row predictablyEnteropens active data rows throughrowActions.onOpenRowSpacetoggles preview when preview is configured- group headers expand and collapse from the keyboard
Esccloses preview before clearing other interaction state- active-row styling is visually distinct from checkbox selection
- grid autofocus helps more than it hurts in the surrounding screen