Getting Started
Using a framework? Jump directly to Angular, React, or Vue.
Quick Start
Section titled “Quick Start”-
Install the package
Terminal window npm install @toolbox-web/gridTerminal window yarn add @toolbox-web/gridTerminal window pnpm add @toolbox-web/gridTerminal window bun add @toolbox-web/gridFor quick prototyping, use the UMD bundle directly:
<script src="https://unpkg.com/@toolbox-web/grid/umd/grid.umd.js"></script> -
Import and use
import '@toolbox-web/grid'; // registers <tbw-grid>import { queryGrid } from '@toolbox-web/grid'; // typed DOM helper -
Add the grid to your HTML
<tbw-grid id="my-grid" style="height: 400px;"></tbw-grid>
Declarative Columns (No JavaScript)
Section titled “Declarative Columns (No JavaScript)”Define columns directly in HTML — great for static layouts and quick prototyping:
<tbw-grid style="height: 400px;"> <tbw-grid-column field="id" header="ID" type="number" sortable></tbw-grid-column> <tbw-grid-column field="name" header="Name"></tbw-grid-column> <tbw-grid-column field="email" header="Email"></tbw-grid-column></tbw-grid>Set rows from JavaScript or via the rows HTML attribute (JSON). See Light DOM Columns for the full attribute reference.
Auto-Inferred Columns
Section titled “Auto-Inferred Columns”Skip column configuration entirely — the grid creates columns from your data:
import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';
const grid = queryGrid('#my-grid');grid.rows = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com', active: true }, { id: 2, name: 'Bob Smith', email: 'bob@example.com', active: false },];// → Creates ID, Name, Email, and Active columns automaticallyThe grid detects types (number, boolean, date, string) from values and formats headers from field names (firstName → First Name). See Column Inference for details.
Framework Integration
Section titled “Framework Integration”The grid is a standard web component that works in any JavaScript environment — you can always use the Vanilla JS approach in any framework. For React, Vue, and Angular, we also provide dedicated adapter packages that enable custom component renderers and editors.
Add a grid element to your HTML, then configure it from JavaScript:
<tbw-grid style="height: 400px;"></tbw-grid>import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';
const grid = queryGrid('tbw-grid');
grid.columns = [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' },];
grid.rows = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];That’s a working grid. From here, add features as you need them — sorting, editing, selection, and more are each a one-line import:
import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';import '@toolbox-web/grid/features/editing';import '@toolbox-web/grid/features/selection';import '@toolbox-web/grid/features/filtering';
const grid = queryGrid('tbw-grid');
grid.gridConfig = { columns: [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name', editable: true }, { field: 'email', header: 'Email', editable: true }, ], features: { editing: 'dblclick', selection: 'row', filtering: true, },};
grid.rows = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];
grid.on('cell-commit', (detail) => console.log('Edited:', detail));See Core Features for renderers, formatters, and custom editors.
For React projects, use the @toolbox-web/grid-react adapter package for enhanced integration:
# Install both packagesnpm install @toolbox-web/grid @toolbox-web/grid-reactimport { DataGrid } from '@toolbox-web/grid-react';
const employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];
function EmployeeGrid() { return ( <DataGrid rows={employees} columns={[ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, ]} style={{ height: 400, display: 'block' }} /> );}That’s a working grid. From here, add features as you need them — each is a one-line import plus a prop:
import '@toolbox-web/grid-react/features/editing';import '@toolbox-web/grid-react/features/selection';import '@toolbox-web/grid-react/features/filtering';
import { DataGrid } from '@toolbox-web/grid-react';
const employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];
function EmployeeGrid() { return ( <DataGrid rows={employees} columns={[ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name', editable: true }, { field: 'email', header: 'Email', editable: true }, ]} editing="dblclick" selection="row" filtering onCellCommit={(e) => console.log('Edited:', e.detail)} style={{ height: 400, display: 'block' }} /> );}The adapter adds JSX renderers/editors, the useGrid hook, and declarative GridColumn components.
See the React adapter docs for custom renderers, editors, and the complete API reference.
For Vue projects, use the @toolbox-web/grid-vue adapter package for enhanced integration:
# Install both packagesnpm install @toolbox-web/grid @toolbox-web/grid-vue<script setup>import { TbwGrid } from '@toolbox-web/grid-vue';
const employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];</script>
<template> <TbwGrid :rows="employees" :columns="[ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, ]" style="height: 400px; display: block;" /></template>That’s a working grid. From here, add features as you need them — each is a one-line import plus a prop:
<script setup>import '@toolbox-web/grid-vue/features/editing';import '@toolbox-web/grid-vue/features/selection';import '@toolbox-web/grid-vue/features/filtering';
import { TbwGrid } from '@toolbox-web/grid-vue';
const employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' },];</script>
<template> <TbwGrid :rows="employees" :columns="[ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name', editable: true }, { field: 'email', header: 'Email', editable: true }, ]" editing="dblclick" selection="row" filtering @cell-commit="(e) => console.log('Edited:', e.detail)" style="height: 400px; display: block;" /></template>The adapter adds slot-based renderers/editors (#cell, #editor), the useGrid composable, and declarative TbwGridColumn components.
See the Vue adapter docs for custom renderers, editors, and the complete API reference.
For Angular projects, use the @toolbox-web/grid-angular adapter package for enhanced integration:
# Install both packagesnpm install @toolbox-web/grid @toolbox-web/grid-angularimport { Component } from '@angular/core';import { Grid } from '@toolbox-web/grid-angular';import type { ColumnConfig } from '@toolbox-web/grid-angular';
@Component({ selector: 'app-employee-grid', imports: [Grid], template: ` <tbw-grid [rows]="employees" [columns]="columns" style="height: 400px; display: block;"> </tbw-grid> `,})export class EmployeeGridComponent { employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' }, ];
columns: ColumnConfig[] = [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, ];}That’s a working grid. From here, add features as you need them — each is a one-line import plus an input binding:
import { GridEditingDirective } from '@toolbox-web/grid-angular/features/editing';import { GridSelectionDirective } from '@toolbox-web/grid-angular/features/selection';import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';import { Component } from '@angular/core';import { Grid } from '@toolbox-web/grid-angular';import type { ColumnConfig } from '@toolbox-web/grid-angular';import type { CellCommitDetail } from '@toolbox-web/grid/plugins/editing';
@Component({ selector: 'app-employee-grid', imports: [Grid, GridEditingDirective, GridSelectionDirective, GridFilteringDirective], template: ` <tbw-grid [rows]="employees" [columns]="columns" [editing]="'dblclick'" [selection]="'row'" [filtering]="true" (cellCommit)="onCellCommit($event)" style="height: 400px; display: block;"> </tbw-grid> `,})export class EmployeeGridComponent { employees = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' }, ];
columns: ColumnConfig[] = [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name', editable: true }, { field: 'email', header: 'Email', editable: true }, ];
// camelCase outputs deliver the unwrapped detail directly ($event is the // detail, not the native CustomEvent). Bind kebab-case (cell-commit) instead // if you need the CustomEvent for event.preventDefault(). onCellCommit(detail: CellCommitDetail) { console.log('Edited:', detail); }}The adapter adds structural directives (*tbwRenderer, *tbwEditor), template-driven renderers/editors, and grid-level event outputs.
See the Angular adapter docs for custom renderers, editors, and the complete API reference.
Plain JavaScript (No Build Step)
Section titled “Plain JavaScript (No Build Step)”This section covers both no-build paths:
- ES module
/allfor declarative HTML-first setup - UMD script tags with global
TbwGridfor classic browser scripting
HTML-first with /all (zero handwritten setup code)
Section titled “HTML-first with /all (zero handwritten setup code)”Use this approach when you want a fully functional grid from plain HTML. The /all bundle auto-registers the grid plus all features/plugins, so you can configure everything with attributes and child elements.
Zero-JS Quickstart
Section titled “Zero-JS Quickstart”-
Add the module script:
<script type="module" src="https://unpkg.com/@toolbox-web/grid/all.js"></script> -
Add a grid with JSON attributes:
<tbw-gridstyle="height: 320px;"rows='[{"id":1,"name":"Alice","status":"active"},{"id":2,"name":"Bob","status":"inactive"}]'grid-config='{"features":{"selection":"row","editing":"dblclick","filtering":true,"export":{"fileName":"employees","includeHeaders":true}}}'><tbw-grid-column field="id" header="ID" type="number" sortable></tbw-grid-column><tbw-grid-column field="name" header="Name" sortable></tbw-grid-column><tbw-grid-column field="status" header="Status" editable></tbw-grid-column></tbw-grid> -
Interact with the grid:
- Sort by clicking any sortable header.
- Filter from header filter controls.
- Select rows.
- Edit
editablecells (double-click in this example).
Declarative columns
Section titled “Declarative columns”Define columns with <tbw-grid-column> children. These attributes cover the full declarative column surface:
| Attribute | Type | Description |
|---|---|---|
field | string | Required field key. Supports field:type shorthand, for example field="price:number". |
header | string | Header text. |
type | string | Column type, for example string, number, boolean, date, select or custom type names. |
width | string | Width such as "120", "100px", "20%". |
min-width | number | Minimum width in pixels. |
sortable | boolean | Enables sorting (presence means true). |
resizable | boolean | Enables resizing (presence means true). |
order | number | Initial 0-based position. |
editable | boolean | Enables inline editing (requires editing feature/plugin). |
options | string | Select options for type="select", for example "a:A,b:B" or "a,b". |
pinned | string | Initial pinning: left/start or right/end (requires pinned-columns plugin). |
hidden | boolean | Initially hidden (requires visibility plugin). |
lock-visible | boolean | Prevents hiding via visibility controls (requires visibility plugin). |
For related declarative elements (<tbw-grid-column-header>, shell/tool-panel elements), see API reference: Light DOM elements.
Template rendering
Section titled “Template rendering”Use <tbw-grid-column-view> for display and <tbw-grid-column-editor> for custom editors.
Supported template expressions:
{{ value }}for the current cell value.{{ row.field }}for other fields on the current row.- Ternaries and simple expressions, for example
{{ row.status === 'active' ? 'ok' : 'bad' }}.
Security boundaries:
- Script execution and event-handler attributes are not allowed in template output.
- HTML-string rendering is sanitized.
- Keep behavior wiring out of templates; these templates are for safe markup/data interpolation.
Live Demo
Section titled “Live Demo”Zero-JS grid setup with declarative columns, filtering, selection, editing, and template-driven rendering.
import '@toolbox-web/grid/all';<tbw-grid style="height: 320px;" rows='[ {"id":1,"name":"Alice","status":"active","department":"Engineering"}, {"id":2,"name":"Bob","status":"inactive","department":"Sales"}, {"id":3,"name":"Carla","status":"active","department":"Support"}, {"id":4,"name":"Dylan","status":"inactive","department":"Engineering"}, {"id":5,"name":"Erin","status":"active","department":"Marketing"} ]' grid-config='{ "features": { "selection": "row", "editing": "dblclick", "filtering": true, "export": { "fileName": "employees", "includeHeaders": true } } }' > <tbw-grid-column field="id" header="ID" type="number" width="80" sortable></tbw-grid-column> <tbw-grid-column field="name" header="Name" sortable resizable></tbw-grid-column>
<tbw-grid-column field="status" header="Status" editable sortable> <tbw-grid-column-view> <span class="status-badge {{ row.status === 'active' ? 'ok' : 'bad' }}">{{ value }}</span> </tbw-grid-column-view> <tbw-grid-column-editor> <select> <option value="active">Active</option> <option value="inactive">Inactive</option> </select> </tbw-grid-column-editor> </tbw-grid-column>
<tbw-grid-column field="department" header="Department" sortable></tbw-grid-column> </tbw-grid>This demo uses only declarative HTML and one /all script import. It includes a conditional badge class and a <select> editor, both expressed entirely in HTML templates.
UMD script-tag usage (global TbwGrid)
Section titled “UMD script-tag usage (global TbwGrid)”If you prefer classic script tags and a global API, use the UMD bundles and configure the grid through window.TbwGrid.
Core UMD bundle
Section titled “Core UMD bundle”<!DOCTYPE html><html><head> <script src="https://unpkg.com/@toolbox-web/grid/umd/grid.umd.js"></script></head><body> <tbw-grid id="my-grid" style="height: 400px;"></tbw-grid> <script> var grid = TbwGrid.queryGrid('#my-grid');
grid.columns = [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, { field: 'email', header: 'Email' }, ];
grid.rows = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' }, ]; </script></body></html>All-in-one UMD bundle (core + plugins)
Section titled “All-in-one UMD bundle (core + plugins)”<script src="https://unpkg.com/@toolbox-web/grid/umd/grid.all.umd.js"></script><script> var grid = TbwGrid.queryGrid('#my-grid');
grid.gridConfig = { columns: [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name', editable: true }, { field: 'email', header: 'Email', editable: true }, ], plugins: [ new TbwGrid.EditingPlugin({ trigger: 'dblclick' }), new TbwGrid.SelectionPlugin({ mode: 'row' }), new TbwGrid.FilteringPlugin(), ], };
grid.rows = [ { id: 1, name: 'Alice Johnson', email: 'alice@example.com' }, { id: 2, name: 'Bob Smith', email: 'bob@example.com' }, { id: 3, name: 'Carol White', email: 'carol@example.com' }, ];</script>Bundle size notes
Section titled “Bundle size notes”/all is the easiest entry point for HTML-first usage and quick prototyping. For application builds where bundle size matters, prefer targeted imports (@toolbox-web/grid plus specific features/* and plugins/*) so your bundler can tree-shake unused modules.
For script-tag usage, grid.umd.js includes core only (~168 kB raw, ~48 kB gzipped), while grid.all.umd.js bundles core + all plugins (~514 kB raw, ~136 kB gzipped). You can also load individual plugin UMD files (for example selection.umd.js) for finer control.
TypeScript Support
Section titled “TypeScript Support”The package ships with full type definitions. Use generics on queryGrid to get typed row data throughout your code:
import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';import type { ColumnConfig } from '@toolbox-web/grid';
interface Employee { id: number; name: string; email: string;}
const grid = queryGrid<Employee>('tbw-grid');
// Column config is type-checked against Employeeconst columns: ColumnConfig<Employee>[] = [ { field: 'id', header: 'ID', type: 'number' }, { field: 'name', header: 'Name' }, // { field: 'typo' } ← TypeScript error!];
// Event payloads are typed toogrid.on('cell-commit', ({ row, field, value }) => { console.log(row.name, field, value); // row is Employee});Nested fields
Section titled “Nested fields”A column field can be a dotted path into nested row data — it is read and
written without a valueAccessor:
interface Deal { id: string; deal: { capture: { field: string; comments: string[] }; otherStuff: { other: string }; };}
const columns: ColumnConfig<Deal>[] = [ { field: 'deal.capture.field' }, { field: 'deal.capture.comments', renderer: (ctx) => (ctx.value as string[]).join(', ') }, { field: 'deal.otherStuff.other' },];Dotted paths work everywhere a plain field does — display, sort, filter, export, editing, and undo/redo. Rules worth knowing:
-
If a column defines a
valueAccessor, it still wins over the dotted-path read. -
If a row literally has an own property named
'deal.comments'(a flat key containing a dot), that flat value is used instead of traversing. -
By default
fieldaccepts any string (dotted paths compile with zero config) while still autocompleting top-level keys. For strict compile-time validation of the full path, opt in with theNestedPathshelper:import type { GridConfig, NestedPaths } from '@toolbox-web/grid';// Typos anywhere in the path are now compile errors.const config: GridConfig<Deal, NestedPaths<Deal>> = {columns: [{ field: 'deal.capture.field' }],};
Next Steps
Section titled “Next Steps”Now that you have the grid set up, explore: