Row operations
Insert, duplicate, and delete rows through props, keyboard shortcuts, and the context menu.
Inserting, duplicating, and deleting whole rows. All three act on view-space indices (the
sorted/filtered positions the user sees), emit one onDataChange with source: "row-op" each,
and work in both controlled and uncontrolled grids.
Enable props
| Prop | Enables | Without it |
|---|---|---|
createRow: (index: number) => TData | Insert row above/below | insertRow is a silent no-op with a dev-only warning; the context menu hides the two Insert items |
duplicateRow: (row: TData) => TData | Duplicate row(s) | duplicateRows is a silent no-op with a dev-only warning; the context menu hides Duplicate |
| (none) | Delete row(s) | Always available |
duplicateRow must give every copy a distinct id (a spread copy with a fresh id), so a
duplicate never collides with its source row's React key. createRow receives the data-space
insertion index.
Default shortcuts
| Action | Default | Keymap action |
|---|---|---|
| Insert row below | Ctrl/Cmd+Shift+F | insertRowBelow |
| Duplicate row(s) | Ctrl/Cmd+Shift+X | duplicateRow |
| Delete row(s) | (no default binding) | (none) |
Both bindings live in DEFAULT_KEYMAP, so they can be remapped or dropped through the keymap
prop like every other binding (see Selection & keyboard).
Context menu
The row-operation items ship with the data-grid-context-menu
add-on, which installs a right-click menu on the grid's cell and header surfaces. Right-clicking
a cell makes it the active cell with a single-cell selection before the menu opens, so the items
always act on a known target.
The cell-surface items, in order:
- Cut / Copy / Paste — the native clipboard pipeline (see Clipboard).
- Clear contents — empties the selection to each type's
clearValue()(thedeleteContentsaction, Delete/Backspace). - Insert row above / Insert row below — anchored at the right-clicked row; hidden without
createRow. - Duplicate row(s) — Ctrl/Cmd+Shift+X; hidden
without
duplicateRow. - Delete row(s) — destructive item, no default keyboard binding.
The row-operation items act on every view row covered by the current selection, falling back
to the right-clicked row when nothing is selected, so a range selection duplicates or deletes all
of its rows at once. Every mutating item (everything but Copy) is disabled on a readOnly grid.
Surfaces with no menu: row markers, the empty grid space below the last row, and the scrollbar gutter right-click to nothing at all, no menu and no browser context menu either, matching the quiet no-op of a plain click on empty space. The header surface gets its own menu (sort, pin, autosize, hide), documented on Columns.
Programmatic actions
import { useDataGridActions } from "@/components/data-grid/data-grid";
function MyToolbar() {
const actions = useDataGridActions();
return (
<button
onClick={() => {
// view-space indices: [0] is the top visible row
actions.insertRow(2, "below");
actions.insertRows(0, 5, "above"); // a row-count dialog is one gesture, one undo step
actions.duplicateRows([1, 2]);
actions.deleteRows([4]);
}}
>
...
</button>
);
}insertRow(viewRowIndex, "above" | "below")inserts one row built bycreateRow.insertRows(viewRowIndex, count, "above" | "below")insertscountrows as ONE batch (oneonDataChange, one history entry) instead ofcountconsecutive gestures.createRowis called once per row with its landing data index. A no-op forcount <= 0.deleteRowsalready takes a range, so this is the batch counterpart of a range delete.duplicateRows(viewRowIndexes)inserts each copy directly after its source row (a duplicate of a range lands interleaved, each after its own source).deleteRows(viewRowIndexes)deletes the named rows in one batch.
Selection behavior: insert and duplicate keep the selection, offsetting it around the inserted
rows. Delete clears the entire selection and the active cell. All three fire onDataChange with
source: "row-op" and id-keyed insert/delete ops, which is what undo/redo and export consume.