Skip to content

Keyboard and selection

View as Markdown

Sapporta Grid treats keyboard behavior as runtime configuration. Choose the interaction model that matches the surface before you customize individual cells.

Common presets include:

PresetUse it for
CELL_EDITING_GRIDEditable spreadsheet behavior with cell focus and range selection.
CELL_EDITING_NO_SELECTION_GRIDEditable cells without range selection.
CELL_GRID_WITH_ACTIVE_ROWEditable cells with active-row highlighting.
CELL_GRID_WITH_INDEPENDENT_ROW_SELECTIONEditable cells with independent bulk row selection.
CELL_PRIMARY_WITH_SIDE_PANEL_ROWEditable cells with a detail panel following the cursor row.
CELL_PRIMARY_WITH_SELECTED_SIDE_PANEL_ROWEditable cells with an independently pinned detail row.
ROW_PRIMARY_MASTER_DETAILRow-first master/detail lists.
ROW_PRIMARY_MASTER_DETAIL_WITH_ACTIVATIONRow-first master/detail lists where Enter and double-click run one action.
ROW_MULTISELECT_LISTMulti-select row lists.

Add a selection column when row selection is part of the workflow:

import { CELL_GRID_WITH_INDEPENDENT_ROW_SELECTION } from "@sapporta/grid";
import { rowSelectionColumn, text } from "@sapporta/grid/column-preset";
const schema = {
rootLevel: "tasks",
levels: {
tasks: {
name: "tasks",
rowHeaderColumn: { column: "__row_selection" },
childLevels: [],
columns: [
rowSelectionColumn(),
text({ id: "title", name: "Title", edit: "default" }),
],
options: {},
},
},
};
const runtime = createGridRuntime({
schema,
dataSource,
interaction: CELL_GRID_WITH_INDEPENDENT_ROW_SELECTION,
});

Let the preset own focus, active row, and selection rules. Custom cells should use the runtime state instead of creating a second keyboard model in component state.

Cell selection and row selection are separate concepts. A cell range is a rectangular selection inside one rendered level. Row selection identifies rows for commands such as delete, export, bulk edit, or opening a side panel. Choose the preset first, then add columns or toolbar actions that use the selected row state.

Active-row state is separate from both selection types. It identifies one current row for a preview or related-record surface. Read the grid-wide value with useGridActiveRow() or runtime.activeRow(). Use a configured rowActivated event for repeatable actions such as opening an edit route.

In a row list, activeRow.keyboard.expansion: "enabled" makes Space toggle the active row’s expansion, Right expand it, and Left collapse it. ROW_PRIMARY_MASTER_DETAIL enables expansion and leaves Enter unassigned. ROW_PRIMARY_MASTER_DETAIL_WITH_ACTIVATION also assigns Enter and double-click to row activation. Shift+Space is reserved for row selection.

ROW_MULTISELECT_LIST keeps an independent multi-row selection. Shift+Space toggles the active row and Shift+Up or Shift+Down extends the selection. With the mouse, a click moves the row cursor, Shift-click selects the range from the row cursor to the clicked row, and Cmd-click or Ctrl-click adds or removes one row. See Row selection for the rules in other configurations.

On a tree level the same keys follow the tree. Right expands a collapsed row or moves to its first child. Left collapses an expanded row or moves to its parent. Space toggles, and a row without children ignores Right and Space. In a cell grid, Space on the tree column toggles the row, and Enter toggles it when the tree cell is not editable.

A plain Delete or Backspace clears the focused editable cell: it writes null, and it does the same for the other selected cells of that column. Clearing is an edit, so it applies only where an editor could open. A column can refuse it with disableBackspaceCellClear: true; a schema-derived TGrid sets that option on notNull columns, so a required cell cannot be emptied with a keystroke while a nullable foreign key can.

Grid copy uses the active cell or cell range. It does not read row selection. Keep row selection for row operations such as delete, export, bulk edit, or side-panel workflows.

Typecheck the example and exercise its visible loading, ready, interaction, and failure states. Use only public @sapporta/grid export paths.

Continue with Interaction configuration and presets.