Skip to main content

Find & Replace

Search the grid the way Excel does: Ctrl+F opens Find, Ctrl+H opens Replace. A compact panel floats at the grid's top-right corner, every match is lightly highlighted, and the current match becomes the active cell.

Live Demo​

Click a cell, then Ctrl+F to find or Ctrl+H to replace (Enter / Shift+Enter to step, Esc to close)
Live

Quick Example​

import { OGrid } from '@alaarab/ogrid-react-radix';

<OGrid
columns={columns}
data={rows}
getRowId={(r) => r.id}
editable
onCellValueChanged={handleChange}
findReplace
/>;

The same prop works on @alaarab/ogrid-react-fluent (the panel uses Fluent v9 Input, Button, Checkbox and Select) and on the bare DataGridTable.

Keyboard​

KeyWhereAction
Ctrl+F (Cmd+F)Grid focusedOpen Find (again: re-select the query)
Ctrl+HGrid focusedOpen Replace (Find only on a read-only grid)
Enter / Shift+EnterFind boxNext / previous match, wrapping at the ends
EnterReplace boxReplace the current match and go to the next
EscapePanelClose and return focus to the active cell

The shortcuts only apply while the grid has focus, so the browser's own find still works everywhere else on the page. While a cell editor is open, Ctrl+F belongs to the editor.

Options​

Open them with the ⋯ button.

OptionDefaultMeaning
Match caseoffUpper/lower case must match
Match entire cell contentsoffThe whole cell text must equal the query
Within selectionoffSearch only the range that was selected when the panel opened (a single-cell selection searches the whole grid, as in Excel)
Search: by rows / by columnsby rowsThe order Enter walks the matches
Look in: values / formulasvaluesValues searches the displayed text (after valueFormatter, dates and booleans formatted; a formula cell's result). Formulas searches the underlying content: the raw value, or a formula cell's formula

What gets searched​

  • Every filtered row, in the current sort order, across all pages. When the next match is on another page, the grid moves to that page.
  • Visible columns only. Hidden columns are not searched.
  • Under virtual scrolling, the grid scrolls the match into view.
  • Covered cells of a merged cell are skipped; the anchor is searched.
  • Server-side and windowed data sources: only the rows the grid holds (the current page, or the loaded rows).
  • With formulas on, the search covers the displayed rows (all rows when not paginated).

The status shows 3 of 12 (or No results) and is announced to screen readers through an aria-live region.

Replace​

Replacement edits go through the same path as typing or pasting:

  • The replaced text is parsed by the column's valueParser (or its built-in type parser). A value the parser rejects is skipped.
  • Each change reaches onCellValueChanged.
  • Replace all is one undo step: Ctrl+Z restores every cell it changed.
  • Cells in read-only columns (or rows where editable returns false) are skipped. The status reports the count, e.g. Replaced 5 cells, 8 skipped.
  • With Look in: values, formula cells are skipped rather than overwritten. With Look in: formulas, a result that starts with = is written as a formula.
  • Matching is literal text: $, * and ? in the query or the replacement have no special meaning.

Headless: useFindReplace​

Building your own table on the headless hooks? useFindReplace holds the panel state, runs the matcher and turns replaces into value changes; you render the panel and decide what "go to a match" means.

import { useFindReplace } from '@alaarab/ogrid-react';

const find = useFindReplace({
rows, // every searchable row, display order
columns, // visible columns
getRowId: (r) => r.id,
activeCell, // { rowIndex, columnIndex } where searching starts
selection, // ISelectionRange for "Within selection"
onNavigate: (m) => { // m: { rowId, columnId, rowIndex, columnIndex }
setActiveCell({ row: m.rowIndex, col: m.columnIndex });
},
onCellEdit: (events) => { // one call per Replace / Replace all
setRows((prev) => applyEvents(prev, events));
},
});

// Ctrl+F: find.open('find'), Ctrl+H: find.open('replace')
<input value={find.query} onChange={(e) => find.setQuery(e.target.value)} />
<span aria-live="polite">{find.statusText}</span>
<button onClick={find.next}>Next</button>
<button onClick={find.replaceAll} disabled={!find.canReplace}>Replace all</button>

The matcher is also available as pure functions: findMatches, findNextMatchIndex, planReplace and replaceInCellText from @alaarab/ogrid-core (re-exported by @alaarab/ogrid-react).

Theming​

CSS variableDefaultUsed for
--ogrid-find-match-bgrgba(255, 213, 0, 0.28)Match highlight
--ogrid-z-find30Panel stacking order