The grid selects cells with the mouse, the keyboard, or code, and runs Sheets-style keyboard shortcuts when it has focus.
console . log ( grid . getSelection ()); // { kind: "cell", addr: { sheet: "sheet1", row: 0, col: 0 } }
Result: A1 is selected, outlined as the active cell.
Full setup
import "@sheetwrite/core/styles.css" ;
const host = document . querySelector < HTMLElement >( "#grid" ); if ( host === null ) throw new Error ( "Missing #grid host" );
columns : { a : new Float64Array ([ 10 , 20 ]), b : new Float64Array ([ 30 , 40 ]) }, console . log ( grid . getSelection ()); // { kind: "cell", addr: { sheet: "sheet1", row: 0, col: 0 } } // Later, clear the selection:
The selection listener runs for each change. getSelection() returns the current selection, or null when nothing is selected. Call grid.setSelection(null) to clear it.
The grid makes its host element focusable (tabindex="0") so that it receives keyboard events.
Try it live → Spreadsheet showcase
Selection model
A Selection is one of five shapes:
| { kind : "multi" ; ranges : Range [] };
How the primary mouse button makes a selection:
Gesture Result Click a cell Select that cell. Drag across cells Extend to a range . Shift-click Extend the range from the current anchor. Ctrl/Cmd-click Add a region. This makes a multi selection. Click a column letter (top header) Select that column (Shift extends; Ctrl/Cmd adds).
Row and full-column selections are part of the model. The top header selects columns. Row selection is programmatic only : there is no row-header click gesture. Set it with setSelection({ kind: "row", sheet, row }).
For touch gestures, see Touch .
Keyboard navigation
When the grid has focus and is not editing:
Key Action Arrow keys Move the focus one cell. Ctrl/Cmd + Arrow Jump to the first/last row or column. Page Up / Page Down Move by a viewport of rows. Home / End Move to the first / last column of the row. Ctrl/Cmd + Home / End Move to the sheet's first / last cell. Shift + any of the above Extend the selection instead of moving. Enter or F2 Edit the focused cell (F2 selects the existing text). Delete / Backspace Clear the selected cells. A printable character Start editing, replacing the cell's content. Ctrl/Cmd + C / X / V Copy / cut / paste. Ctrl/Cmd + Z Undo the last edit. Ctrl/Cmd + Shift + Z (or Ctrl/Cmd + Y) Redo. Ctrl/Cmd + F Open the find bar (when config.find is not false).
The keys inside the inline editor are on Editing and clipboard .
Rebind an action
Use config.keyboard.bindings to replace the keys for one action. Omitted actions keep their defaults. Use null to remove an action's keys, or an array for multiple bindings. These bindings apply when the grid has focus and is not editing.
The Copy label is ⌘⇧C on macOS and Ctrl+Shift+C elsewhere. Its original Mod+C binding no longer runs Copy. Menu actions use their bound shortcut by default; shortcut: "copy" lets a custom item use the same label. Built-in toolbar titles and grid.getShortcutLabel("copy") use the same keymap.
Write a key combination
Write a key combination as a string or as an object:
A string lists modifiers and then one key: "Mod+Shift+K", "Ctrl+Alt+Delete". The modifiers are Mod, Ctrl, Meta, Alt and Shift, in any order.
An object names the key and its modifiers: { key: "k", mod: true, shift: true }. Use the object form for a key without modifiers, for example { key: "F2" }.
Mod shows as Command on macOS and as Control on other systems. It accepts either key, so the same shortcut works with a Mac keyboard and a PC keyboard. Ctrl and Meta are always exactly the Control and Command (or Windows) keys, so "Ctrl+J" is Control+J on a Mac too. Shift and Alt must match exactly.
Name the key as printed without Shift: "Mod+Shift+1" and "Mod+Shift+/" run when the user presses Shift with the 1 or / key, although the browser reports ! and ? for those presses. Letters and digits keep their meaning on other keyboard layouts.
Add a shortcut for your own command
Give a context-menu item a shortcut and an onClick. The grid then runs onClick when the grid has focus and the user presses that combination, with the focused cell as the cell argument. A combination with Mod, Ctrl or Meta also works while the inline editor is open. A hidden or disabled item does not run.
if ( cell ) console . log ( "open record for row" , cell . row );
Pressing Mod+Shift+O logs the focused cell's row.
Options
config.keyboard valueEffect true (default)The stock bindings in the table above. { bindings }Replace the keys of the named actions. Omitted actions keep their defaults; null removes an action's keys. falseTurn off all built-in keys. The host handles every key. (e, grid) => booleanIntercept each keydown before the defaults. Return true to consume the key, or false to let the built-in handler continue.
The actions you can rebind are copy, cut, paste, pasteValues, undo, redo, find, replace and clearContents. See KeyboardOptions and KeyShortcut .
Edge cases and limits
Only the pointer that began a drag can change it. Switching sheets, changing sheet structure or the sorted/filtered view, or losing pointer capture ends the gesture. A later pointer release cannot apply it to a different sheet or view.
If two commands use the same combination, createGrid and setConfig throw a SheetwriteError with code shortcut-conflict, and setConfig keeps the previous configuration.
A malformed combination throws code invalid-shortcut.
readOnly: true keeps navigation and selection, but turns off the keys that change cells.
See also
const grid: Grid const grid : Grid const grid : Grid The imperative core grid this controller owns. API reference → Grid.on<"selection">(evt: "selection", fn: (e: {
selection: Selection | null;
}) => void): () => void Grid. on < "selection" >(evt: "selection" , fn: ( e : {
selection : Selection | null ;
}) => void ): () => void Grid. on < "selection" >(evt: "selection" , fn: ( e : {
selection : Selection | null ;
}) => void ): () => void e: {
selection: Selection | null;
} let e : {
selection : Selection | null ;
} let e : {
selection : Selection | null ;
} API reference → var console: Console var console : Console var console : Console Console.log(...data: any[]): void (+1 overload) Console. log ( ... data: any[]): void ( + 1 overload) Console. log ( ... data: any[]): void ( + 1 overload) The console.log() static method outputs a message to the console. MDN Reference selection: Selection | null let selection : Selection | null let selection : Selection | null CSS color painted over the selected region. API reference → Grid.setSelection(sel: Selection | null): void Grid. setSelection (sel: Selection | null ): void Grid. setSelection (sel: Selection | null ): void kind: "cell" let kind : "cell" let kind : "cell" Selects one addressed cell. addr: CellAddress let addr : CellAddress let addr : CellAddress Zero-based data address of the selected cell. API reference → CellAddress.sheet: string interface CellAddress {
sheet : string ;
} interface CellAddress {
sheet : string ;
} Sheet identity used by the simple data-first adapter. Defaults to sheet1. API reference → CellAddress.row: number interface CellAddress {
row : number ;
} interface CellAddress {
row : number ;
} 0-based row of the cell that holds the top-left corner. API reference → CellAddress.col: number interface CellAddress {
col : number ;
} interface CellAddress {
col : number ;
} 0-based column of the cell that holds the top-left corner. API reference → Grid.getSelection(): Selection | null Grid. getSelection (): Selection | null Grid. getSelection (): Selection | null function createGrid(host: HTMLElement, opts: GridOptions): Grid function createGrid (
host : HTMLElement ,
opts : GridOptions ,
) : Grid function createGrid (
host : HTMLElement ,
opts : GridOptions ,
) : Grid Creates and mounts an imperative Grid in the supplied host element. Example import { createGrid, initSheetwrite } from "@sheetwrite/core" ;
await initSheetwrite ();
const host = document. createElement ( "div" );
host.style.height = "400px" ;
document.body. append (host);
const grid = createGrid (host, {
workbook: {
activeSheet: "sales" ,
sheets: [{ id: "sales" , name: "Sales" , rowCount: 2 ,
columns: [{ key: "amount" , header: "Amount" , type: "number" , width: 120 }] }],
},
data: { rowCount: 2 , columns: { amount: [ 12 , 18 ] } },
});
grid. scrollToCell ({ sheet: "sales" , row: 1 , col: 0 });
// Call when the host view is removed.
grid. destroy (); See also Grid * See also GridOptions API reference → function initSheetwrite(source?: BufferSource | URL | string | Request | WebAssembly.Module, engine?: SheetwriteEngine): Promise<void> function initSheetwrite (
source ?:
BufferSource | URL | string | Request | WebAssembly . Module ,
engine ?: SheetwriteEngine ,
) : Promise < void > function initSheetwrite (
source ?:
| BufferSource
| URL
| string
| Request
| WebAssembly . Module ,
engine ?: SheetwriteEngine ,
) : Promise < void > Load one WASM engine before createGrid. The default is @sheetwrite/wasm. Pass the @sheetwrite/formulas module as the second argument to select the full engine. Example import { initSheetwrite } from "@sheetwrite/core" ;
import * as formulas from "@sheetwrite/formulas" ;
await initSheetwrite ( undefined , formulas); See also /docs/start/choose-an-engine/ See also createGrid API reference → interface ColumnarData interface ColumnarData interface ColumnarData Eager column-oriented values used to initialize a sheet. API reference → interface Workbook interface Workbook interface Workbook Live workbook schema containing ordered sheets and the active sheet ID. API reference → const host: HTMLElement | null const host : HTMLElement | null const host : HTMLElement | null var document: Document var document : Document var document : Document window.document returns a reference to the document contained in the window. MDN Reference API reference → ParentNode.querySelector<HTMLElement>(selectors: string): HTMLElement | null (+4 overloads) ParentNode. querySelector < HTMLElement >(selectors: string): HTMLElement | null ( + 4 overloads) ParentNode. querySelector < HTMLElement >(selectors: string): HTMLElement | null ( + 4 overloads) Returns the first element that is a descendant of node that matches selectors. MDN Reference interface HTMLElement interface HTMLElement interface HTMLElement The HTMLElement interface represents any HTML element. MDN Reference var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+2 overloads) var Error : ErrorConstructor
new ( message ?: string , options ?: ErrorOptions ) => Error ( + 2 overloads) var Error : ErrorConstructor
new ( message ?: string , options ?: ErrorOptions ) => Error ( + 2 overloads) const host: HTMLElement const host : HTMLElement const host : HTMLElement ElementCSSInlineStyle.style: CSSStyleDeclaration interface ElementCSSInlineStyle {
style : CSSStyleDeclaration ;
} interface ElementCSSInlineStyle {
style : CSSStyleDeclaration ;
} MDN Reference API reference → CSSStyleDeclaration.height: string interface CSSStyleDeclaration {
height : string ;
} interface CSSStyleDeclaration {
height : string ;
} MDN Reference API reference → const workbook: Workbook const workbook : Workbook const workbook : Workbook Live workbook schema adopted by the store and updated by document operations. API reference → Workbook.activeSheet: string interface Workbook {
activeSheet : string ;
} interface Workbook {
activeSheet : string ;
} Active sheet ID and initial tab presented when the grid is created. API reference → Workbook.sheets: Sheet[] interface Workbook {
sheets : Sheet [];
} interface Workbook {
sheets : Sheet [];
} Sheets in display/tab order. API reference → Sheet.id: string interface Sheet {
id : string ;
} interface Sheet {
id : string ;
} Stable identifier, unique within the workbook and used by every cell address. API reference → Sheet.name: string interface Sheet {
name : string ;
} interface Sheet {
name : string ;
} User-facing sheet name shown in tabs and workbook exports. API reference → Sheet.rowCount: number interface Sheet {
rowCount : number ;
} interface Sheet {
rowCount : number ;
} Row count for both in-memory and datasource-backed sheets. API reference → Sheet.columns: Column[] interface Sheet {
columns : Column [];
} interface Sheet {
columns : Column [];
} Ordered schema; array positions are the zero-based column coordinates. API reference → Column.key: string interface Column {
key : string ;
} interface Column {
key : string ;
} Non-empty key, unique within the sheet, used to map input and datasource values. API reference → Column.header: string interface Column {
header : string ;
} interface Column {
header : string ;
} Schema label used by table exports and data-grid presentation headers. API reference → Column.type: CellFormat interface Column {
type : CellFormat ;
} interface Column {
type : CellFormat ;
} Controls cell input parsing and default value formatting for this column. API reference → Column.width: number interface Column {
width : number ;
} interface Column {
width : number ;
} Unzoomed column width in CSS pixels. API reference → const data: ColumnarData const data : ColumnarData const data : ColumnarData Eager column-major values loaded into workbook.activeSheet; use instead of datasource. API reference → ColumnarData.rowCount: number interface ColumnarData {
rowCount : number ;
} interface ColumnarData {
rowCount : number ;
} Row count for both in-memory and datasource-backed sheets. API reference → ColumnarData.columns: Record<string, ArrayLike<CellScalar | CellValue>> interface ColumnarData {
columns : Record < string , ArrayLike < CellScalar | CellValue >>;
} interface ColumnarData {
columns : Record <
string ,
ArrayLike <
CellScalar | CellValue
>
>;
} Exact column runs represented by every returned row. API reference → a: Float64Array<ArrayBuffer> let a : Float64Array < ArrayBuffer > let a : Float64Array < ArrayBuffer > var Float64Array: Float64ArrayConstructor
new (elements: Iterable<number>) => Float64Array<ArrayBuffer> (+6 overloads) var Float64Array : Float64ArrayConstructor
new ( elements : Iterable < number >) => Float64Array < ArrayBuffer > ( + 6 overloads) var Float64Array : Float64ArrayConstructor
new ( elements : Iterable < number >) => Float64Array < ArrayBuffer > ( + 6 overloads) b: Float64Array<ArrayBuffer> let b : Float64Array < ArrayBuffer > let b : Float64Array < ArrayBuffer > GridOptions.workbook: Workbook interface GridOptions {
workbook : Workbook ;
} interface GridOptions {
workbook : Workbook ;
} Live workbook schema adopted by the store and updated by document operations. API reference → GridOptions.data?: ColumnarData | undefined interface GridOptions {
data ?: ColumnarData | undefined ;
} interface GridOptions {
data ?: ColumnarData | undefined ;
} Eager column-major values loaded into workbook.activeSheet; use instead of datasource. API reference → type Selection = {
kind: "cell";
addr: CellAddress;
} | {
kind: "range";
range: Range;
} | {
kind: "row";
sheet: SheetId;
row: number;
} | {
kind: "column";
sheet: SheetId;
col: number;
} | {
kind: "multi";
ranges: Range[];
}
type Selection = {
kind: "cell";
addr: CellAddress;
} | {
kind: "range";
range: Range;
} | {
kind: "row";
sheet: SheetId;
row: number;
} | {
kind: "column";
sheet: SheetId;
col: number;
} | {
kind: "multi";
ranges: Range[];
} type Selection =
| {
kind : "cell" ;
addr : CellAddress ;
}
| {
kind : "range" ;
range : Range ;
}
| {
kind : "row" ;
sheet : SheetId ;
row : number ;
}
| {
kind : "column" ;
sheet : SheetId ;
col : number ;
}
| {
kind : "multi" ;
ranges : Range [];
};
type Selection =
| {
kind : "cell" ;
addr : CellAddress ;
}
| {
kind : "range" ;
range : Range ;
}
| {
kind : "row" ;
sheet : SheetId ;
row : number ;
}
| {
kind : "column" ;
sheet : SheetId ;
col : number ;
}
| {
kind : "multi" ;
ranges : Range [];
}; type Selection =
| {
kind : "cell" ;
addr : CellAddress ;
}
| {
kind : "range" ;
range : Range ;
}
| {
kind : "row" ;
sheet : SheetId ;
row : number ;
}
| {
kind : "column" ;
sheet : SheetId ;
col : number ;
}
| {
kind : "multi" ;
ranges : Range [];
};
type Selection =
| {
kind : "cell" ;
addr : CellAddress ;
}
| {
kind : "range" ;
range : Range ;
}
| {
kind : "row" ;
sheet : SheetId ;
row : number ;
}
| {
kind : "column" ;
sheet : SheetId ;
col : number ;
}
| {
kind : "multi" ;
ranges : Range [];
}; Current cell, range, row, column, or multi-range selection. API reference → interface CellAddress interface CellAddress interface CellAddress Zero-based address of one cell on a stable sheet ID. API reference → range: Range let range : Range let range : Range Inclusive table rectangle on one stable sheet ID. API reference → interface Range interface Range interface Range The Range interface represents a fragment of a document that can contain nodes and parts of text nodes. MDN Reference API reference → sheet: string let sheet : string let sheet : string Sheet identity used by the simple data-first adapter. Defaults to sheet1. API reference → type SheetId = string type SheetId = string ; type SheetId = string ; Stable identifier used to address a workbook sheet. API reference → row: number let row : number let row : number 0-based row of the cell that holds the top-left corner. API reference → col: number let col : number let col : number 0-based column of the cell that holds the top-left corner. API reference → Grid.setConfig(config: GridConfig | undefined): void Grid. setConfig (config: GridConfig | undefined ): void Grid. setConfig (config: GridConfig | undefined ): void Reconfigure built-in chrome and keyboard handling without replacing the Grid or clearing selection/history. Construction-bound GridOptions are not accepted here. API reference → GridConfig.keyboard?: boolean | KeyboardOptions | ((e: KeyboardEvent, grid: Grid) => boolean) | undefined interface GridConfig {
keyboard ?:
| boolean
| KeyboardOptions
| (( e : KeyboardEvent , grid : Grid ) => boolean )
| undefined ;
} interface GridConfig {
keyboard ?:
| boolean
| KeyboardOptions
| ((
e : KeyboardEvent ,
grid : Grid ,
) => boolean )
| undefined ;
} Built-in keyboard handling. true (default) keeps the stock Sheets-style bindings. An object replaces individual action bindings; omitted actions keep their defaults, and null disables an action's keys. For example: { bindings: { copy: { key: "c", mod: true, shift: true } } }. Menu hints and toolbar titles use these same bindings. false disables all built-in keys. A function intercepts each keydown before the defaults; return true to consume it, false to let the built-in handler continue. API reference → KeyboardOptions.bindings?: Partial<Record<KeyboardAction, KeyShortcut | readonly KeyShortcut[] | null>> | undefined interface KeyboardOptions {
bindings ?:
| Partial <
Record <
KeyboardAction ,
KeyShortcut | readonly KeyShortcut [] | null
>
>
| undefined ;
} interface KeyboardOptions {
bindings ?:
| Partial <
Record <
KeyboardAction ,
| KeyShortcut
| readonly KeyShortcut []
| null
>
>
| undefined ;
} copy?: KeyShortcut | readonly KeyShortcut[] | null | undefined copy ?: KeyShortcut | readonly KeyShortcut[] | null | undefined copy ?: KeyShortcut | readonly KeyShortcut[] | null | undefined Copy the focused rectangle to the system clipboard. Never rejects. API reference → find?: KeyShortcut | readonly KeyShortcut[] | null | undefined find ?: KeyShortcut | readonly KeyShortcut[] | null | undefined find ?: KeyShortcut | readonly KeyShortcut[] | null | undefined Open the built-in find bar when it is enabled. API reference → key: string let key : string let key : string Non-empty key, unique within the sheet, used to map input and datasource values. API reference → mod?: boolean | undefined mod ?: boolean | undefined mod ?: boolean | undefined replace?: KeyShortcut | readonly KeyShortcut[] | null | undefined replace ?: KeyShortcut | readonly KeyShortcut[] | null | undefined replace ?: KeyShortcut | readonly KeyShortcut[] | null | undefined Atomically replaces one document queue only if its ordered IDs still match the caller's expected view. API reference → GridConfig.contextMenu?: boolean | ContextMenuItems | undefined interface GridConfig {
contextMenu ?: boolean | ContextMenuItems | undefined ;
} interface GridConfig {
contextMenu ?:
| boolean
| ContextMenuItems
| undefined ;
} Built-in menu, disabled menu, static rows, or a request-aware row factory. API reference → ContextMenuItem.action?: ContextMenuActionName | undefined interface ContextMenuItem {
action ?: ContextMenuActionName | undefined ;
} interface ContextMenuItem {
action ?:
| ContextMenuActionName
| undefined ;
} Built-in action to bind (or "separator"). Omit when supplying onClick. API reference → ContextMenuItem.label?: string | undefined interface ContextMenuItem {
label ?: string | undefined ;
} interface ContextMenuItem {
label ?: string | undefined ;
} Menu row text. Defaults per action. API reference → ContextMenuItem.shortcut?: KeyboardAction | KeyShortcut | undefined interface ContextMenuItem {
shortcut ?: KeyboardAction | KeyShortcut | undefined ;
} interface ContextMenuItem {
shortcut ?:
| KeyboardAction
| KeyShortcut
| undefined ;
} A bound action name or a custom key combination. An explicit combination registers onClick as a keyboard command; action names only reference the existing built-in binding. Both forms display platform-aware labels. For example, shortcut: "copy" follows the configured Copy binding, while shortcut: "Mod+Shift+K" binds this item's onClick callback. See KeyboardOptions for built-in action overrides. API reference → ContextMenuItem.id?: string | undefined interface ContextMenuItem {
id ?: string | undefined ;
} interface ContextMenuItem {
id ?: string | undefined ;
} Stable host identifier, exposed as data-context-menu-item. API reference → ContextMenuItem.onClick?: ((grid: Grid, cell: CellAddress | null) => void) | undefined interface ContextMenuItem {
onClick ?:
(( grid : Grid , cell : CellAddress | null ) => void ) | undefined ;
} interface ContextMenuItem {
onClick ?:
| ((
grid : Grid ,
cell : CellAddress | null ,
) => void )
| undefined ;
} Custom click handler; receives the grid and the right-clicked cell (null if none). API reference → _grid: Grid let _grid : Grid let _grid : Grid API reference → cell: CellAddress | null let cell : CellAddress | null let cell : CellAddress | null Right-clicked cell, or null when the pointer is outside the cell body. API reference → cell: CellAddress let cell : CellAddress let cell : CellAddress Right-clicked cell, or null when the pointer is outside the cell body. API reference →