GridSheet Props
The GridSheet component accepts the following props to configure its behavior and appearance.
Props Overview
| Prop | Type | Required | Description |
|---|---|---|---|
initialCells | CellsByAddressType | Yes | Initial cell data and configuration |
sheetName | string | No | Unique identifier for the sheet |
book | BookType | No | Shared book for cross-sheet communication |
sheetRef | RefObject<SheetHandle | null> | No | Ref to access the sheet and its sync function |
storeRef | RefObject<StoreHandle | null> | No | Ref to access the store and dispatch function |
options | OptionsType | No | Configuration options for sheet behavior |
className | string | No | CSS class name for styling |
style | CSSProperties | No | Inline styles for the component |
Initial Cells
The initialCells prop defines the starting data and configuration for your spreadsheet. This is where you specify cell values, styles, renderers, policies, and other cell-specific settings.
Cell data is designed to be JSON-serializable (see Serialization Design), so you can persist the cells to a database or localStorage and restore them later by passing them back as initialCells. See Example 5 — Multi-sheet Excel clone for a working example with localStorage persistence.
Important: This is the initial value given to the sheet. Changes made after initialization will not be reflected, so please be careful.
Performance guideline: For smooth performance, we recommend keeping the total number of cells at around 2,000,000 or fewer (e.g. 200,000 rows × 10 columns). Beyond that threshold, initial data generation and memory consumption may start to degrade the user experience. See Example 8 — Large Dataset for a working demo at this scale.
Address Format
The format uses cell addresses as keys for cell configuration objects. For example, to set the text color of D3 to green, use {D3: {style: {color: "#00FF00"}}}.
Default Configuration
The default key applies a base configuration to all cells in the spreadsheet, which is useful for setting global shared styles. However, width and height cannot be set via default.
To set a global default width or height that applies to all headers, use the defaultCol and defaultRow keys instead:
const initialCells = {
// Applies to all cells in the sheet
default: {
style: { fontSize: '14px' }
},
// Base configuration for all column headers
defaultCol: {
width: 100
},
// Base configuration for all row headers
defaultRow: {
height: 30
},
'A1': { value: 'Hello World' },
'B2': { value: 100 },
};Header Configuration
Header dimensions are configured using the 0 key for the corner cell (sets default header height/width):
const initialCells = {
// Corner cell: default header row height and column header width
'0': {
height: 60, // Header row height
width: 80, // Row header width
},
'A1': { value: 'Hello World' },
};Header Cell Addressing (ch(), rh(), A0:G0)
To configure individual column or row header cells, you should use the ch() and rh() utility functions provided by @gridsheet/react-core. While internally GridSheet appends a 0 (e.g., A0, 01), Using the ch and rh functions is strongly recommended.
ch('A')(evaluates toA0) — Column A's header cell only (width, label, style, etc.)rh(1)(evaluates to01) — Row 1's header cell only (height, style, etc.)A0:G0— Range of column header cells (A through G)
import { ch, rh } from '@gridsheet/react-core';
const initialCells = {
// Column A header: set width and label
[ch('A')]: { width: 150, label: 'Product' },
// Row 1 header: set height
[rh(1)]: { height: 50 },
// Style column headers F and G blue
'F0:G0': { style: { color: 'blue' } },
// All data cells in column A (does NOT affect the header)
A: { style: { backgroundColor: '#eef' } },
};Note: A: { ... } applies to all data cells in column A (rows 1 and below). Use ch('A') to target the column A header cell. Similarly, 1: { ... } applies to all data cells in row 1; use rh(1) for the row 1 header.
Column and Row Specifications
For columns and rows, you can specify using only one side of the address:
- Columns: Use just the column letter (e.g.,
Dfor column D) - Rows: Use just the row number (e.g.,
3for row 3)
Column/Row Specific Properties
Some properties are only valid for columns or rows:
| Property | Valid For | Description |
|---|---|---|
width | Column header keys only (ch('A'), defaultCol) | Column width in pixels |
height | Row header keys only (rh(1), defaultRow) | Row height in pixels |
label | Column header keys only (ch('A')) | Custom display text for the column header |
Note: width, height, and label are header-only properties. Specifying them on data cell keys like A, 1, or D3 has no effect. Furthermore, they will not work on the generic default key.
Cell Configuration
Each cell can be configured with the following properties:
| Property | Type | Description |
|---|---|---|
value | T | The cell's content (text, numbers, formulas). You can parse user input and store arbitrary values, but avoid non-serializable objects like class instances. Cell values are designed to be serializable (except for system field). |
style | CSSProperties | CSS properties for appearance |
justifyContent | CSSProperties['justifyContent'] | Horizontal alignment within the cell |
alignItems | CSSProperties['alignItems'] | Vertical alignment within the cell |
label | string | Fixed custom display text for column headers (columns only). Takes precedence over labeler if both are specified. |
width | Width | Cell width in pixels |
height | Height | Cell height in pixels |
policy | string | Key of a policy registered in the book |
custom | Custom | Custom data for the cell. You can store any arbitrary data here for your application's needs |
formulaEnabled | boolean | Enable formula evaluation for this cell (default: true) |
prevention | OperationType | Operation restrictions for the cell |
sortFixed | boolean | Row header only. Prevents this row from being reordered during sort operations |
filterFixed | boolean | Row header only. Prevents this row from being hidden during filter operations |
Important Notes:
- Serialization: Cell values (except
systemfield) are designed to be serializable. Avoid storing non-serializable objects like class instances. - System Field: The
systemfield contains values used by the system to display correct values. Do not modify this field manually.
Fixed Rows (sortFixed / filterFixed)
sortFixed and filterFixed are row-level flags that keep specific rows anchored when the user sorts or filters the sheet. They are set on the row header cell, addressed as '0<row>' (column 0, the row header column).
import { rh } from '@gridsheet/react-core';
buildInitialCells({
cells: {
B6: { value: 'Total' },
C6: { value: '=SUM(C1:C5)' },
'6': { style: { borderTop: '3px double #555' } },
// Row 6 header cell — fix during sort and filter
[rh(6)]: { sortFixed: true, filterFixed: true },
},
})| Flag | Effect |
|---|---|
sortFixed | The row stays in its original position when any column is sorted. Other rows move around it. |
filterFixed | The row is never hidden regardless of active filter conditions. |
Rows with filterFixed show a ‹ prefix and rows with sortFixed show a › suffix in their row header, rendered automatically via CSS ::before/::after pseudo-elements.
Prevention Flags
The prevention property uses bitwise flags from the operations export to restrict specific operations on cells, columns, or rows. Multiple flags can be combined with the | (OR) operator.
import { operations } from '@gridsheet/react-core';| Flag | Value | Description |
|---|---|---|
RemoveRows | 1 | Prevent removing rows |
RemoveCols | 2 | Prevent removing columns |
InsertRowsAbove | 4 | Prevent inserting rows above |
InsertRowsBelow | 8 | Prevent inserting rows below |
InsertColsLeft | 16 | Prevent inserting columns to the left |
InsertColsRight | 32 | Prevent inserting columns to the right |
MoveFrom | 64 | Prevent moving cells from this location |
MoveTo | 128 | Prevent moving cells to this location |
Write | 256 | Prevent editing cell values |
Style | 512 | Prevent changing cell styles |
Resize | 1024 | Prevent resizing rows/columns |
Copy | 8192 | Prevent copying cells |
SetPolicy | 16384 | Prevent changing cell policy |
Sort | 32768 | Prevent sorting by this column |
Filter | 65536 | Prevent filtering by this column |
SetLabel | 131072 | Prevent editing the column header label |
Convenience aliases:
| Alias | Combines | Description |
|---|---|---|
Move | MoveFrom | MoveTo | Prevent all move operations |
ReadOnly | Write | Style | Move | Copy | Prevent all data modifications |
ViewOnly | ReadOnly | Resize | Prevent all modifications including resize |
// Prevent sorting and filtering on column C
{
C: {
prevention: operations.Sort | operations.Filter,
},
}
// Column with a custom label, protected from label editing
{
A: {
label: 'Name',
prevention: operations.SetLabel,
},
}Example Usage
import { ch, rh } from '@gridsheet/react-core';
const initialCells = {
// Default configuration for all cells
default: {
style: { fontSize: '14px' }
},
defaultCol: { width: 100 },
defaultRow: { height: 30 },
// Header configuration
'0': {
height: 60, // Header row height
width: 80, // Header column width
},
// Individual cell configuration
'A1': { value: 'Hello World', style: { color: '#FF0000' } },
'B2': { value: 100, policy: 'currency' },
'C3': { value: 'Active', policy: 'status' },
// Column header configuration (width, label only affect headers)
[ch('A')]: { width: 150, label: 'Name' }, // A0
[ch(2)]: { width: 200, label: 'Value' }, // B0
// Style for all data cells in column A
'A': { style: { backgroundColor: '#f9f9f9' } },
// Row header configuration
[rh(1)]: { height: 40 }, // 01
[rh(2)]: { height: 50 }, // 02
};
<GridSheet initialCells={initialCells} />Book-Registered Components
The policy property references a Policy instance registered in the book by its string key. A Policy unifies rendering, parsing, serialization, and header-label logic.
Example Usage
import { useBook } from '@gridsheet/react-core';
const book = useBook({
policies: {
currency: new Policy({ mixins: [CurrencyPolicyMixin] }),
status: new Policy({ mixins: [StatusPolicyMixin] }),
},
});
// In initialCells configuration
{
'A1': {
value: 1000,
policy: 'currency',
style: { backgroundColor: '#f0f9ff' },
},
'B1': {
value: 'Active',
policy: 'status',
},
}Note: The system property is managed internally by GridSheet and should not be specified manually.
Sheet Name
A unique identifier for the sheet that enables cross-sheet references and communication. When multiple sheets share a book, the sheet name is used to distinguish between them for formula calculations and data sharing.
Sheet names must be unique within the same book. When sharing a book across multiple GridSheet components, each component must be given a distinct sheetName. Duplicate names will cause cross-sheet formula references (e.g. ='Sheet1'!A1) to break and may result in incorrect sheet IDs.
const book = useBook({});
// ✅ Correct — each sheet has a unique name
<GridSheet book={book} sheetName="Sheet1" initialCells={...} />
<GridSheet book={book} sheetName="Sheet2" initialCells={...} />
// ❌ Incorrect — duplicate names within the same book
<GridSheet book={book} sheetName="Sheet1" initialCells={...} />
<GridSheet book={book} sheetName="Sheet1" initialCells={...} />sheetRef / storeRef
sheetRef and storeRef are refs that give you programmatic access to the sheet and store from outside the GridSheet component.
Types
type SheetHandle = {
sheet: UserSheet;
apply: (sheet: UserSheet) => void;
};
type StoreHandle = {
store: StoreType;
apply: (store: StoreType) => void;
dispatch: Dispatcher;
};Creating refs
Use the provided hooks (inside a component) or factory functions (outside):
import { useSheetRef, useStoreRef, createSheetRef, createStoreRef } from '@gridsheet/react-core';
// Inside a component
const sheetRef = useSheetRef();
const storeRef = useStoreRef();
// Outside a component (e.g. in a class or module)
const sheetRef = createSheetRef();
const storeRef = createStoreRef();sheetRef — programmatic sheet updates
Use sheetRef when you need to read or mutate the sheet data from outside the component:
const sheetRef = useSheetRef();
const handleUpdate = () => {
if (!sheetRef.current) return;
const { sheet, apply } = sheetRef.current;
apply(sheet.update({ diff: { A1: { value: 'Hello' } } }));
};
<GridSheet sheetRef={sheetRef} initialCells={...} />storeRef — store access and applyers
Use storeRef when you need to trigger UI-level operations (insert/remove rows, undo/redo, etc.) via applyers.
StoreHandle has the same shape as StoreDispatchType, so you can pass storeRef.current directly to any applyers function:
import { useStoreRef, applyers } from '@gridsheet/react-core';
const storeRef = useStoreRef();
const handleInsert = () => {
if (!storeRef.current) return;
applyers.insertRowsAbove(storeRef.current); // pass directly — no destructuring needed
};
<GridSheet storeRef={storeRef} initialCells={...} />storeRef.current.dispatch is the raw Redux-style dispatcher. applyers functions need it because they fire multiple distinct actions internally (not just a single store patch). The sync shortcut on StoreHandle only covers simple store patches via setStore.
Using both refs together
You can pass both at the same time:
const sheetRef = useSheetRef();
const storeRef = useStoreRef();
<GridSheet sheetRef={sheetRef} storeRef={storeRef} initialCells={...} />Book
The book enables communication between multiple GridSheet instances. Use the useBook hook to create a shared book that allows sheets to reference each other's data in formulas.
import { useBook } from '@gridsheet/react-core';
// or, to include all extended formula functions:
import { useSpellbook } from '@gridsheet/react-core/spellbook';Book Configuration
The useBook hook accepts configuration options that are shared across all sheets using the same book:
| Option | Type | Description |
|---|---|---|
historyLimit | number | Maximum number of history entries for undo/redo |
additionalFunctions | FunctionMapping | Custom formula functions |
policies | { [policyName: string]: PolicyType } | Custom cell policies |
onSave | FeedbackType | Callback when cell data is saved |
onChange | FeedbackType | Callback when cell data changes |
onRemoveRows | (args: { sheet: UserSheet; ys: number[] }) => void | Callback when rows are removed from the spreadsheet |
onRemoveCols | (args: { sheet: UserSheet; xs: number[] }) => void | Callback when columns are removed from the spreadsheet |
onInsertRows | (args: { sheet: UserSheet; y: number; numRows: number }) => void | Callback when rows are inserted into the spreadsheet |
onInsertCols | (args: { sheet: UserSheet; x: number; numCols: number }) => void | Callback when columns are inserted into the spreadsheet |
onSelect | FeedbackType | Callback when cell selection changes |
onKeyUp | (args: { e: EditorEvent; points: CursorStateType }) => void | Callback when a key is pressed in the cell editor |
onInit | (args: { sheet: UserSheet }) => void | Callback when the sheet is initialized |
Event Handler Sheet Identification
When multiple sheets share the same book, event handlers receive a sheet parameter that contains the UserSheet instance. You can use sheet.name to identify which sheet triggered the event:
const book = useBook({
onChange: ({ sheet, points }) => {
if (sheet.name === 'Sales') {
console.log('Sales sheet data changed:', points);
} else if (sheet.name === 'Inventory') {
console.log('Inventory sheet data changed:', points);
}
},
onRemoveRows: ({ sheet, ys }) => {
console.log(`Rows removed from ${sheet.name}:`, ys);
},
onInsertCols: ({ sheet, x, numCols }) => {
console.log(`Inserted ${numCols} columns at position ${x} in ${sheet.name}`);
},
onKeyUp: ({ e, points }) => {
console.log(`Key pressed: ${e.key} at position:`, points);
},
onInit: ({ sheet }) => {
console.log(`Sheet initialized: ${sheet.name}`);
},
});Important: Always use sheet.name for conditional logic when multiple sheets share the same book to ensure proper event handling and data management.