Skip to main content
A key press in the grid becomes a GridIntent from tally-core. The grid then acts on the intent: it moves the selection, starts an edit, copies, undoes. onIntent on <Tally> sees each intent first, so the host can add commands, open its own panels or block an action.

The intents

keyboardIntent in tally-core produces these. The right column is what tally-react does when onIntent does not consume the intent. Copy uses the column types’ formatted text. Clear, cut and paste skip columns with editable: false and do nothing when the source cannot mutate. See Editing and validation.

Keys

The primary modifier is Command on macOS and Control elsewhere. tally-react reads the platform from navigator.platform. Enter, F2, Delete and typing need an active cell. Tab on the first or last column is not captured, so focus leaves the grid. Under dir="rtl" Left and Right are swapped before the lookup. See RTL. While an editor is open, the grid does not handle keys. The editor owns them until it commits or cancels.

onIntent

onIntent has the type IntentHandler: (intent: GridIntent) => boolean | undefined. Return true to consume the intent. Return anything else to let the grid handle it.
accounts.tsx
This handler opens an inspector on Space and blocks cut and clear. Copy, paste and everything else still work.

Pointer input

Mouse input does not go through intents. A click focuses a cell, Shift + click extends the range, a drag selects a range and a double click opens the editor. The grid dispatches those to grid.selection directly. Clicks on links, buttons and inputs inside a cell are left alone. Watch pointer selection with grid.selection.subscribe or useSelection(grid).

Without React

keyboardIntent(input, state, geometry, options?) is a pure function. A host that renders its own grid maps key events with it and dispatches select intents to the selection store.
host.ts
See Selection and keyboard for the selection actions and reducer.