gridcn1.2.2

Find & replace

The data-grid-find-replace add-on: a panel that finds text in the grid and replaces one match or all matches as one undoable change.

Users fix the same typo in many cells without editing each cell. data-grid-find-replace adds a panel with a Find field and a Replace field. useDataGridFindReplace returns the plugin that mounts the panel and binds Mod+F to open Find and Ctrl+H to open Find and Replace.

Press Ctrl+H inside the grid to open the panel.

Name
Email
Role
Age
Silent Tiger
user0@example.com
Viewer
63
Quick Lion
user1@example.com
Viewer
67
Swift Wolf
user2@example.com
Manager
40
Eager Lion
user3@example.com
User
50
Eager Tiger
user4@example.com
Viewer
45
Silent Wolf
user5@example.com
User
24
Swift Lion
user6@example.com
Viewer
34
Eager Lion
user7@example.com
Manager
21
Eager Eagle
user8@example.com
Editor
25
Bold Tiger
user9@example.com
Editor
19
Bold Bear
user10@example.com
User
42
Swift Wolf
user11@example.com
Manager
47
Swift Bear
user12@example.com
Viewer
41
Eager Wolf
user13@example.com
Editor
35
Swift Eagle
user14@example.com
Viewer
65
Quick Lion
user15@example.com
Manager
22
Bold Wolf
user16@example.com
Editor
30
Swift Eagle
user17@example.com
Admin
19
Eager Eagle
user18@example.com
Manager
35
Eager Bear
user19@example.com
Editor
33
Silent Lion
user20@example.com
Manager
48
Silent Tiger
user21@example.com
Manager
62
Eager Tiger
user22@example.com
Manager
51
Silent Lion
user23@example.com
Admin
26
Bold Eagle
user24@example.com
Admin
26
Bold Lion
user25@example.com
Viewer
49
Quick Tiger
user26@example.com
Viewer
26
Bold Eagle
user27@example.com
Editor
50
Swift Tiger
user28@example.com
Editor
55
Silent Lion
user29@example.com
Viewer
35
pnpm dlx shadcn@latest add @gridcn/data-grid-find-replace

Pass the plugin to the grid:

import { useDataGridFindReplace } from "@/components/data-grid-find-replace/data-grid-find-replace";

const findReplace = useDataGridFindReplace();

<DataGridProvider {...grid} columns={columns} plugins={[findReplace.plugin]}>
  <DataGridRoot>
    <DataGridHeader />
    <DataGridBody />
  </DataGridRoot>
</DataGridProvider>;

findReplace.open(mode) opens the panel from your own button. mode is "replace" (the default) to show the Replace field, or "find" to show Find only. findReplace.close() closes it.

Find

The Find field writes the grid's quick search. The highlights, the next and previous buttons, and the cells that Replace changes are always the same cells. The toolbar search shows the same text.

The search is a literal text match. It never reads the text as a pattern. Two icon toggles sit inside the right side of the Find field and change the match. A pressed toggle has a filled background and a small dot at its corner.

  • Match case matches letter case. It is off by default.
  • Whole cell matches only cells that equal the Find text. It is off by default.

The Previous and Next buttons follow the field. Their tooltips name the keys: Enter goes to the next match and Shift+Enter to the previous one.

The status line is the last row of the panel and keeps one line height. Text that does not fit is cut off, and the title holds the full text. It shows 2 of 4 cells for the current match, No results when nothing matches, and Type to search while the Find field is empty. The number gets a + when the highlight list stops at its cap. The Replace row adds its own row to the panel and removes it again.

Find ignores leading and trailing spaces in the Find text. Pass the same options to the store with actions.setSearch(text, { matchCase, wholeCell }). The options stay set until the next call that sets them.

Replace

A cell is matched on its search text. This is the text the user sees, for example the label of a select choice. Replace swaps the Find text in that text and then converts the result with the column type's fromText. A select label maps back to its value. A number cell parses again.

  • Replace changes the current match, then moves to the next match. When the active cell is a match, Replace changes that cell.
  • Replace all changes every matching cell in the view.

Each click writes one change with the source "replace". One undo reverts it. Selection and active cell stay where they are.

Replace skips a cell when:

  • the column or the row is read-only,
  • the replaced text cannot become a value of the type (replacing 5 with x in a number column leaves the cell as it is),
  • the replaced text is longer than 100,000 characters,
  • the column's validate rejects the new value. onValidationError receives these cells with the source "replace".

The Replace row holds the Replace field, the Replace button, and the Replace all button. The same status line shows how many cells changed and how many were skipped. With an async validate, it shows Validating… until the batch settles.

Where Replace works

Replace covers the visible columns of the rows in the view. Hidden columns, filtered-out rows, pinned rows, and unloaded lazy rows never change. With scope: "selection", it covers only the selected cells.

One Replace all changes at most replaceAllLimit cells. When more cells match, the status line says so. Click Replace all again to continue. The next click skips the cells the earlier one changed, even when the replacement contains the find text. A change to the find text, the replacement, or an option starts over.

The chevron button at the start of the Find row shows and hides the Replace field. The panel keeps the Find text when you toggle it. Every open sets the Replace field: Mod+F and open("find") hide it, and Ctrl+H and open("replace") show it.

When the grid is readOnly, the Find field works. The chevron button is not shown, and Replace stays disabled. While a cell editor is open, Replace does nothing.

A sort or filter on a replaced column does not move rows while the panel is open. The view reconciles on the next sort or filter change. See reorder in Streaming updates.

Keyboard

KeyWhereAction
Mod+FgridOpens the panel with the cursor in Find. The Replace field stays hidden.
Ctrl+HgridOpens the panel with the cursor in Find and the Replace field shown.
EnterFindGoes to the next match.
Shift+EnterFindGoes to the previous match.
EnterReplaceReplaces the current match.
Mod+EnterReplaceReplaces all matches.
EscapepanelCloses the panel. Focus returns to the grid when the panel opened while the grid had focus.

Ctrl is the physical Ctrl key on every platform. Cmd+H hides the app on macOS, and a page cannot take it. Mod is Cmd on macOS and Ctrl elsewhere. Outside the grid, Mod+F opens the browser's own find bar. To change a key, bind openFindReplace or openFind in the grid's keymap.

When the grid also shows DataGridSearch, Mod+F with focus in the grid opens this panel, not the toolbar search. The panel and the toolbar search show the same text.

Options

PropTypeDefaultDescription
scope"view" | "selection""view"Which cells Replace covers.
replaceAllLimitnumber10000Most cells one Replace all changes. Clamped to 1 to 100,000.

planReplace

planReplace(state, find, replacement, options) is the pure function behind the buttons. Its options are scope, replaceAllLimit, matchCase, wholeCell, only, and skip. It returns { patches, skipped, remaining } and writes nothing. Pass patches to actions.updateCells(patches, { source: "replace" }) to write them. options.only limits the plan to one { rowId, columnId } cell. options.skip takes a function that receives a { rowId, columnId } cell and returns true to leave the cell out of the plan. Each entry of skipped has a reason: "readonly", "unparseable", "too-long", or "no-occurrence". "no-occurrence" marks a matched cell whose text holds no occurrence of the Find text to replace. Find and replacement text longer than 1,000 characters is cut.

Labels

The panel strings live under labels.findReplace. See Internationalization.

Ctrl+H opens the browser history in some browsers

The panel calls preventDefault on Ctrl+H while the grid has focus. A browser that reserves the key still opens its history. Bind another key in keymap, or use findReplace.open() from a button.

On this page