Find Next and Previous in Data Grids
Permalink to "Find Next and Previous in Data Grids"Find next and find previous turn a list of highlighted matches into something a keyboard user can actually reach. The interaction is familiar from every text editor: type a query, press Enter to jump to the first match, press Enter again for the next one, Shift+Enter to go back. In a data grid there is an extra requirement — the jump must move real grid focus to the matched cell, so the user lands in a position where arrow keys, row actions and screen reader table commands work from that point.
This guide belongs to table search and match highlighting.
Spec reference
Permalink to "Spec reference"- SC 2.1.1 Keyboard (A) — every match must be reachable from the keyboard; a highlight you can only see is not enough.
- SC 2.4.3 Focus Order (A) — after a jump, focus is on the matched cell, and continuing navigation from there follows the grid’s normal order.
- SC 2.4.7 Focus Visible (AA) — the matched cell shows a focus indicator, distinct from the match highlight.
- SC 4.1.3 Status Messages (AA) — “Match 3 of 12” is a status message; the cell’s content is announced by the focus move itself.
- SC 2.1.4 Character Key Shortcuts (A) — do not bind bare letters like “n” for next unless they can be turned off or remapped.
The grid’s focus model is defined by the ARIA grid pattern: either roving tabindex or aria-activedescendant. The find feature must use the same mechanism the grid already uses.
When to use — and when not to
Permalink to "When to use — and when not to"Use find next/previous when the grid keeps all rows and the user needs to inspect matches in context — for example, finding every mention of a supplier in a ledger while still seeing the neighbouring rows.
Do not build it when filtering is what users want. If the task is “show me only overdue invoices”, a filter that removes non-matching rows is simpler to use and to announce; see searching versus filtering a data grid.
Do not override Ctrl+F (Cmd+F). Browser find is the tool many screen reader and magnifier users rely on, and it already works in non-virtualized tables. If the grid is virtualized and browser find cannot see off-screen rows, offer your own find on a different shortcut and say so in the keyboard shortcut help dialog.
Annotated code example
Permalink to "Annotated code example"// matches: [{ rowIndex, colIndex }] computed from data in reading order (row, then column)
let matches = [];
let current = -1;
const status = document.getElementById('grid-search-count'); // role="status" (SC 4.1.3)
searchInput.addEventListener('keydown', (e) => {
if (e.key !== 'Enter' || matches.length === 0) return;
e.preventDefault();
const step = e.shiftKey ? -1 : 1;
const next = current + step;
const wrapped = next >= matches.length || next < 0;
current = (next + matches.length) % matches.length;
const { rowIndex, colIndex } = matches[current];
grid.scrollToRow(rowIndex); // virtualized grids must render the row first
grid.focusCell(rowIndex, colIndex); // same API the arrow keys use (SC 2.4.3)
markCurrent(rowIndex, colIndex); // outline on the current mark (SC 2.4.7)
// Position message after the focus move; wrap stated explicitly
status.textContent = `Match ${current + 1} of ${matches.length}` +
(wrapped ? (step > 0 ? ', wrapped to first' : ', wrapped to last') : '');
});
// Escape in the grid returns to the search field so users can refine the query
grid.element.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && matches.length) { searchInput.focus(); }
});
A design point that matters: Enter moves focus out of the search field and into the grid. To find the next match the user must go back — so either keep a “Next match” button reachable with Tab, or accept F3 from inside the grid too. Most teams do both.
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"| Key | Action | Expected announcement | Failure indicator |
|---|---|---|---|
| Enter (in field) | Focus first or next match | Cell content and coordinates, then “Match 1 of 12” | Nothing spoken; focus stayed in field |
| Shift+Enter | Previous match | Cell content, “Match 11 of 12” | Moves forward instead |
| F3 / Shift+F3 (in grid) | Next / previous match | As above | Browser’s own find bar opens |
| Escape (in grid) | Back to search field | “Search invoices, edit, overdue” | Escape closes an unrelated panel |
| Enter past the last match | Wraps to first | “…Match 1 of 12, wrapped to first” | Silent jump to the top |
Integration context
Permalink to "Integration context"Find next depends on the match list produced by highlighting search matches with the mark element and the count from announcing match counts. In paginated grids, a match on another page should move to that page first and announce the page change, as in announcing page changes in paginated tables.
Gotchas
Permalink to "Gotchas"Focusing a row that is not rendered. In a virtualized grid, the target row may not exist in the DOM. Scroll it into the rendered window and wait a frame before focusing, or focus will silently fail.
Status message racing the focus announcement. If the status text is set in the same tick as focus moves, some readers speak the status first and the cell second, or drop one. Set the status after focus in a short timeout (50–100 ms).
Stale match list after sorting. Sorting changes reading order. Recompute matches after every sort and filter, and reset the current index to the match nearest the focused cell rather than to zero.
Testing checklist
Permalink to "Testing checklist"Design system notes
Permalink to "Design system notes"Find belongs to the grid’s public API — findNext(), findPrevious() and a matches property — so the search field, a toolbar button and a keyboard shortcut all drive the same logic. Document the default shortcuts in the component’s keyboard contract and make them configurable, because products that embed several grids on one page need to avoid collisions.
FAQ
Permalink to "FAQ"Should Enter in the search field move focus into the grid?
Yes for a dedicated find feature, because the user’s goal is the matched cell. Keep a visible “Next match” button and F3 so they can continue without returning to the field.
Is it acceptable to override Ctrl+F in a virtualized grid?
No. Offer your own find on another shortcut and document it. Overriding browser find takes away a tool many users depend on everywhere else.
How should matches be ordered?
In reading order — row by row, then left to right within a row (right to left in RTL layouts) — so “next” agrees with what arrow-key navigation would reach.
Related
Permalink to "Related"- Announcing match counts — the count message
- Searching versus filtering — choosing the right feature
- Roving tabindex for custom grids — the focus mechanism find relies on