API Reference
GridSheet Props

GridSheet Props

The GridSheet component accepts the following props to configure its behavior and appearance.

Props Overview

PropTypeRequiredDescription
initialCellsCellsByAddressTypeYesInitial cell data and configuration
sheetNamestringNoUnique identifier for the sheet
bookBookTypeNoShared book for cross-sheet communication
sheetRefRefObject<SheetHandle | null>NoRef to access the sheet and its sync function
storeRefRefObject<StoreHandle | null>NoRef to access the store and dispatch function
optionsOptionsTypeNoConfiguration options for sheet behavior
classNamestringNoCSS class name for styling
styleCSSPropertiesNoInline 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 to A0) — Column A's header cell only (width, label, style, etc.)
  • rh(1) (evaluates to 01) — 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., D for column D)
  • Rows: Use just the row number (e.g., 3 for row 3)

Column/Row Specific Properties

Some properties are only valid for columns or rows:

PropertyValid ForDescription
widthColumn header keys only (ch('A'), defaultCol)Column width in pixels
heightRow header keys only (rh(1), defaultRow)Row height in pixels
labelColumn 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:

PropertyTypeDescription
valueTThe 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).
styleCSSPropertiesCSS properties for appearance
justifyContentCSSProperties['justifyContent']Horizontal alignment within the cell
alignItemsCSSProperties['alignItems']Vertical alignment within the cell
labelstringFixed custom display text for column headers (columns only). Takes precedence over labeler if both are specified.
widthWidthCell width in pixels
heightHeightCell height in pixels
policystringKey of a policy registered in the book
customCustomCustom data for the cell. You can store any arbitrary data here for your application's needs
formulaEnabledbooleanEnable formula evaluation for this cell (default: true)
preventionOperationTypeOperation restrictions for the cell
sortFixedbooleanRow header only. Prevents this row from being reordered during sort operations
filterFixedbooleanRow header only. Prevents this row from being hidden during filter operations

Important Notes:

  • Serialization: Cell values (except system field) are designed to be serializable. Avoid storing non-serializable objects like class instances.
  • System Field: The system field 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 },
  },
})
FlagEffect
sortFixedThe row stays in its original position when any column is sorted. Other rows move around it.
filterFixedThe 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';
FlagValueDescription
RemoveRows1Prevent removing rows
RemoveCols2Prevent removing columns
InsertRowsAbove4Prevent inserting rows above
InsertRowsBelow8Prevent inserting rows below
InsertColsLeft16Prevent inserting columns to the left
InsertColsRight32Prevent inserting columns to the right
MoveFrom64Prevent moving cells from this location
MoveTo128Prevent moving cells to this location
Write256Prevent editing cell values
Style512Prevent changing cell styles
Resize1024Prevent resizing rows/columns
Copy8192Prevent copying cells
SetPolicy16384Prevent changing cell policy
Sort32768Prevent sorting by this column
Filter65536Prevent filtering by this column
SetLabel131072Prevent editing the column header label

Convenience aliases:

AliasCombinesDescription
MoveMoveFrom | MoveToPrevent all move operations
ReadOnlyWrite | Style | Move | CopyPrevent all data modifications
ViewOnlyReadOnly | ResizePrevent 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:

OptionTypeDescription
historyLimitnumberMaximum number of history entries for undo/redo
additionalFunctionsFunctionMappingCustom formula functions
policies{ [policyName: string]: PolicyType }Custom cell policies
onSaveFeedbackTypeCallback when cell data is saved
onChangeFeedbackTypeCallback when cell data changes
onRemoveRows(args: { sheet: UserSheet; ys: number[] }) => voidCallback when rows are removed from the spreadsheet
onRemoveCols(args: { sheet: UserSheet; xs: number[] }) => voidCallback when columns are removed from the spreadsheet
onInsertRows(args: { sheet: UserSheet; y: number; numRows: number }) => voidCallback when rows are inserted into the spreadsheet
onInsertCols(args: { sheet: UserSheet; x: number; numCols: number }) => voidCallback when columns are inserted into the spreadsheet
onSelectFeedbackTypeCallback when cell selection changes
onKeyUp(args: { e: EditorEvent; points: CursorStateType }) => voidCallback when a key is pressed in the cell editor
onInit(args: { sheet: UserSheet }) => voidCallback 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.