TypeScript Setup
Configure TypeScript for type-safe ZenGrid development with current public APIs.
ZenGrid ships TypeScript declarations with @zengrid/core. Use the exported Grid class for runtime code and type imports for interfaces.
Imports
import { Grid, type ColumnDef, type GridOptions, type GridEvents } from '@zengrid/core';import type { CellRange, FilterModel, SortState } from '@zengrid/core';import '@zengrid/core/dist/styles.css'; 💡 Tip
Use type imports for interfaces and event payload types so bundlers only keep runtime values that are actually needed.
Typed Options
GridOptions is container-agnostic. Pass the DOM container as the first Grid constructor argument.
import { Grid, type ColumnDef, type GridOptions } from '@zengrid/core';
const columns: ColumnDef[] = [ { field: 'id', header: 'ID', width: 80, sortable: true }, { field: 'name', header: 'Name', width: 220, sortable: true, filterable: true }, { field: 'department', header: 'Department', width: 180, filterable: true },];
const options: GridOptions = { rowCount: 2, colCount: columns.length, rowHeight: 36, colWidth: columns.map((column) => column.width ?? 140), columns, enableSelection: true, enableMultiSelection: true, selectionType: 'range', enableKeyboardNavigation: true, overscanRows: 10, overscanCols: 5,};
const grid = new Grid(document.getElementById('grid')!, options);grid.setData([ [1, 'Alice', 'Engineering'], [2, 'Bob', 'Sales'],]);grid.render();Mapping Typed Records
The frontend data path uses any[][]. Keep your application records typed, then map them into row arrays for the grid.
interface Employee { id: number; name: string; email: string; active: boolean;}
const employees: Employee[] = [ { id: 1, name: 'Alice', email: 'alice@example.com', active: true }, { id: 2, name: 'Bob', email: 'bob@example.com', active: false },];
const columns: ColumnDef[] = [ { field: 'id', header: 'ID', width: 80 }, { field: 'name', header: 'Name', width: 200 }, { field: 'email', header: 'Email', width: 260 }, { field: 'active', header: 'Active', width: 100, renderer: 'checkbox' },];
const rows = employees.map((employee) => [ employee.id, employee.name, employee.email, employee.active,]);
grid.setData(rows);Event Types
GridEvents contains the event payload map. You can either let TypeScript infer payloads from grid.on() or name the payload type explicitly.
type SelectionChange = GridEvents['selection:change'];
grid.on('cell:click', ({ cell, value, nativeEvent }) => { console.log(cell.row, cell.col, value, nativeEvent.button);});
grid.on('cell:doubleClick', ({ cell }) => { console.log('double clicked', cell);});
grid.on('selection:change', (event: SelectionChange) => { console.log(event.ranges);});
grid.on('edit:commit', ({ cell, oldValue, newValue }) => { console.log('edited', cell, oldValue, newValue);});
grid.on('sort:change', ({ sortState }) => { console.log(sortState);});
grid.on('filter:change', ({ filterState }) => { console.log(filterState);});Common Types
const range: CellRange = { startRow: 0, startCol: 0, endRow: 4, endCol: 2,};
const sortState: SortState[] = [ { column: 1, direction: 'asc', sortIndex: 0 },];
const filterState: FilterModel[] = [ { column: 2, conditions: [{ operator: 'contains', value: '@example.com' }], logic: 'AND', },];
grid.sort.setState(sortState);grid.filter.setState(filterState);State Persistence
Use the namespaced state API for snapshots.
const snapshot = grid.state.getSnapshot();localStorage.setItem('gridState', JSON.stringify(snapshot));
const saved = localStorage.getItem('gridState');if (saved) { grid.state.applySnapshot(JSON.parse(saved));}TypeScript Configuration
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "lib": ["ES2020", "DOM"], "moduleResolution": "bundler", "strict": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true }}Reusable Helper
function createEmployeeGrid(container: HTMLElement, employees: Employee[]) { const grid = new Grid(container, { rowCount: employees.length, colCount: columns.length, rowHeight: 36, colWidth: columns.map((column) => column.width ?? 140), columns, });
grid.setData( employees.map((employee) => [ employee.id, employee.name, employee.email, employee.active, ]) );
return grid;}