Skip to content

React Integration

The @witqq/spreadsheet-react package provides WitTable<TRow>, a generic React component that wraps the core canvas engine with React-friendly props, callbacks, and an imperative ref API.

Terminal window
npm install @witqq/spreadsheet @witqq/spreadsheet-react
import { WitTable } from '@witqq/spreadsheet-react';
<WitTable<MyRow>
columns={columns}
data={data}
onCellChange={handleCellChange}
onReady={handleReady}
/>

All WitEngineConfig props pass through to the core engine (columns, data, theme, frozenColumns, frozenRows, etc.).

interface WitTableCallbacks {
onCellChange?: (event: CellChangeEvent) => void;
onSelectionChange?: (event: SelectionChangeEvent) => void;
onSortChange?: (event: SortChangeEvent) => void;
onFilterChange?: (event: FilterChangeEvent) => void;
onScroll?: (event: ScrollEvent) => void;
onReady?: () => void;
}
CallbackFires when
onCellChangeA cell value is edited (includes row, col, oldValue, newValue)
onSelectionChangeActive cell or selection range changes
onSortChangeColumn sort is applied or cleared
onFilterChangeFilter is applied, changed, or removed
onScrollThe viewport scrolls
onReadyThe engine is fully initialized and rendered

Use useRef<WitTableRef> for imperative control:

interface WitTableRef {
getInstance(): WitEngine;
focus(): void;
getSelection(): Selection;
selectCell(row: number, col: number): void;
getCell(row: number, col: number): CellData | undefined;
setCell(row: number, col: number, value: CellValue): void;
undo(): void;
redo(): void;
scrollTo(x: number, y: number): void;
requestRender(): void;
installPlugin(plugin: WitPlugin): void;
removePlugin(name: string): void;
print(): void;
}
MethodDescription
getInstance()Access the underlying WitEngine directly
focus()Focus the table canvas
getSelection()Current selection state
selectCell(row, col)Programmatically select a cell
getCell(row, col)Read cell data
setCell(row, col, value)Write a cell value (triggers change event)
undo() / redo()Command history navigation
scrollTo(x, y)Scroll to pixel position
requestRender()Force a canvas re-render
installPlugin(plugin)Install a plugin at runtime
removePlugin(name)Remove a plugin by name
print()Trigger print layout

WitTable reacts to prop changes:

  • data — updates the cell store and re-renders
  • theme — propagates to all subsystems (canvas layers, editor overlay, tooltips)
  • columns — updates column definitions and layout
import { useRef, useState, useCallback } from 'react';
import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
import type { ColumnDef } from '@witqq/spreadsheet';
interface Employee {
name: string;
department: string;
salary: number;
active: boolean;
}
const columns: ColumnDef[] = [
{ key: 'name', title: 'Name', width: 180, type: 'string' },
{ key: 'department', title: 'Department', width: 140, type: 'string' },
{ key: 'salary', title: 'Salary', width: 120, type: 'number', sortable: true },
{ key: 'active', title: 'Active', width: 80, type: 'boolean' },
];
const data: Employee[] = [
{ name: 'Alice', department: 'Engineering', salary: 95000, active: true },
{ name: 'Bob', department: 'Marketing', salary: 72000, active: true },
{ name: 'Carol', department: 'Engineering', salary: 110000, active: false },
];
function App() {
const ref = useRef<WitTableRef>(null);
const [rows, setRows] = useState(data);
const handleCellChange = useCallback((event) => {
console.log(`Cell [${event.row},${event.col}]: ${event.oldValue}${event.newValue}`);
}, []);
return (
<WitTable<Employee>
ref={ref}
columns={columns}
data={rows}
onCellChange={handleCellChange}
onReady={() => console.log('Table ready')}
/>
);
}
function Controls({ tableRef }: { tableRef: RefObject<WitTableRef> }) {
return (
<div>
<button onClick={() => tableRef.current?.undo()}>Undo</button>
<button onClick={() => tableRef.current?.redo()}>Redo</button>
<button onClick={() => tableRef.current?.scrollTo(0, 0)}>Go to top</button>
<button onClick={() => tableRef.current?.print()}>Print</button>
<button onClick={() => {
const sel = tableRef.current?.getSelection();
console.log('Selection:', sel);
}}>
Log Selection
</button>
</div>
);
}
import { useRef, useEffect } from 'react';
import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
import { FormulaPlugin, ExcelPlugin, ConditionalFormattingPlugin } from '@witqq/spreadsheet-plugins';
function App() {
const ref = useRef<WitTableRef>(null);
useEffect(() => {
const table = ref.current;
if (!table) return;
table.installPlugin(new FormulaPlugin());
table.installPlugin(new ExcelPlugin());
table.installPlugin(new ConditionalFormattingPlugin());
return () => {
table.removePlugin('formula');
table.removePlugin('excel');
table.removePlugin('conditional-format');
};
}, []);
return <WitTable ref={ref} columns={columns} data={data} />;
}