gridcn1.2.2

Global shortcuts

Opt-in undo, redo, and other grid actions for focus positions outside the grid.

The keyboard shortcuts of the grid work only while DOM focus is inside the grid. When focus is on a custom toolbar, a side panel, or body, Ctrl/Cmd+Z does not touch the grid. DataGridGlobalShortcuts mounts a window-level listener that keeps undo and redo active at every focus position.

Edit a cell, then click the button or the input below (focus leaves the grid) and press Ctrl/Cmd+Z — the undo still lands in the grid. Typing into the input? Ctrl/Cmd+Z undoes the input's text, never the grid.

Name
Score
Silent Tiger
4
Quick Lion
89
Swift Wolf
80
Eager Lion
51
Eager Tiger
83
Silent Wolf
15
pnpm dlx shadcn@latest add @gridcn/data-grid-global-shortcuts-demo

How it works

DataGridGlobalShortcuts is a headless component in the core block. It renders nothing. Mount it inside DataGridRoot. The component listens for keydown on the window. A gate of seven rules decides whether an event reaches the grid:

  1. While IME composition is in progress, the gate skips the event.
  2. When the event is already defaultPrevented, the gate skips it. (The page or the grid handled it first.)
  3. When the event target is an editable element (input, textarea, select, contenteditable), the gate skips it. The field keeps its native undo and redo.
  4. When the target is inside a grid, the gate skips the event. The handler inside that grid owns the key.
  5. The gate requires this grid to be the last focused grid with the component. This rule breaks ties between grids.
  6. While an edit session is open, the gate skips the event. The editor owns the key, also in a popup such as the select list.
  7. The key must resolve to an enabled action through the effective keymap.

When the gate passes, the component dispatches the action through the in-grid keymap. For undo and redo, that is the undo/redo command of the data-grid-history plugin. The global shortcut behaves exactly like the in-grid mod+Z binding. With the data-grid-history add-on, undo reverses grid edits. Without the add-on the layer is a no-op, like in-grid undo.

Usage

Mount the component inside DataGridRoot:

import { DataGridGlobalShortcuts } from "@/components/data-grid/data-grid";

function OrdersGrid() {
  return (
    <>
      {/* your custom toolbar — OUTSIDE the grid */}
      <MyToolbar />
      <DataGridProvider {...grid} columns={columns}>
        <DataGridRoot>
          <DataGridGlobalShortcuts />
          <DataGridHeader />
          <DataGridBody />
        </DataGridRoot>
      </DataGridProvider>
    </>
  );
}

Enable one or more actions with a true flag:

<DataGridGlobalShortcuts selectAll deleteRows />

Omit every flag to enable the default set (undo and redo). Setting any flag replaces the default set with exactly the flags you pass.

PropDescriptionDefault
undoenables the effective keymap's undo binding on window keydown. Requires the Undo & redo add-onenabled when no flag is set
redoenables the effective keymap's redo bindings on window keydown. Requires the Undo & redo add-onenabled when no flag is set
fillDownenables the fill-down binding on window keydown. Requires the Fill add-onoff
fillRightenables the fill-right binding on window keydown. Requires the Fill add-onoff
selectAllenables the select-all binding on window keydownoff
insertRowAboveenables the insert-row-above binding on window keydownoff
insertRowBelowenables the insert-row-below binding on window keydownoff
duplicateRowenables the duplicate-row binding on window keydownoff
deleteRowsenables the delete-rows binding on window keydownoff

Each flagged action runs the same dispatch as its in-grid binding, with the same guards. For example, insertRowBelow does nothing without createRow.

The listener reads the effective keymap from the store. When you remap undo, the global binding follows (see Keybindings: Remapping).

Only actions whose every binding includes Ctrl/Cmd (mod) are available as flags. A key without it types into the page, and a ctrl-only or alt-only chord collides with the operating system (Ctrl+Space switches the input language on Windows).

Multiple grids

When several grids with the component share a page, the last focused grid owns the shortcut. When focus moves to grid B, undo and redo target the history of B. Until focus returns to grid A, they target the history of A. A grid without the component never claims the shortcut. If you add the component to one of two grids, nothing changes until you focus that grid. In a tabbed layout, the last DOM focus decides the active tab. When your app switches tabs without a focus change, call undo imperatively for the active tab.

Page-wide mod+z

If your app registers its own window-level mod+z (for example, a global undo), both listeners see the same event. The handler that calls preventDefault first wins. When event.defaultPrevented is true, your handler skips the event. This protects the layer from your listener and your listener from the layer.

Out of scope

  • Global copy and paste: the active cell is unknown while focus is outside the grid. For a programmatic paste, call useDataGridClipboard().pasteFromClipboard().
  • Global navigation: the arrow keys have no mod prefix, so they stay with the page.
  • Global select-all by default: the page owns mod+a until you set the selectAll flag.

On this page