API Reference
Complete reference for the <tbw-grid> component API.
Element Tag
Section titled “Element Tag”<tbw-grid></tbw-grid>The custom element is registered as tbw-grid (Toolbox Web Grid).
Properties
Section titled “Properties”Core Data Properties
Section titled “Core Data Properties”| Property | Type | Default | Description |
|---|---|---|---|
rows | T[] | [] | Array of row data objects |
columns | ColumnConfig[] | [] | Column configuration array |
gridConfig | GridConfig<T> | {} | Full configuration object |
Layout Properties
Section titled “Layout Properties”| Property | Type | Default | Description |
|---|---|---|---|
fitMode | 'stretch' | 'fixed' | 'stretch' | Column sizing strategy |
State Properties
Section titled “State Properties”| Property | Type | Default | Description |
|---|---|---|---|
loading | boolean | LoadingContext | false | Grid-level loading state with optional renderer |
columnState | GridColumnState[] | - | Get/set column widths, order, visibility, sort |
Read-only Properties
Section titled “Read-only Properties”| Property | Type | Description |
|---|---|---|
changedRows | T[] | Rows with pending edits (requires EditingPlugin) |
sortState | Map<string, SortState> | Current sort state per column |
Declarative Configuration
Section titled “Declarative Configuration”The grid supports two forms of declarative HTML configuration:
- HTML Attributes — JSON-serialized values on the
<tbw-grid>element itself - Light DOM Elements — Child elements nested inside
<tbw-grid>for more readable markup
Both approaches can be combined. Light DOM elements take precedence over JSON attributes for the same configuration (e.g., <tbw-grid-column> elements override the columns attribute).
HTML Attributes
Section titled “HTML Attributes”Attributes on the <tbw-grid> element for simple or programmatically-generated configuration:
| Attribute | Maps to Property | Type | Description |
|---|---|---|---|
rows | rows | JSON | Row data as JSON array |
columns | columns | JSON | Column config as JSON array |
grid-config | gridConfig | JSON | Full config object as JSON |
fit-mode | fitMode | string | 'stretch' or 'fixed' |
<tbw-grid rows='[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' columns='[{"field":"id","header":"ID"},{"field":"name","header":"Name"}]' fit-mode="stretch"></tbw-grid>Light DOM Elements
Section titled “Light DOM Elements”Child elements inside <tbw-grid> for more readable, template-friendly configuration. Preferred for framework templates (Angular, Vue, etc.) and complex column setups with custom renderers/editors.
Column Elements
Section titled “Column Elements”<tbw-grid-column>
Section titled “<tbw-grid-column>”Define column configuration declaratively.
| Attribute | Type | Description |
|---|---|---|
field | string | Required. Data field key |
header | string | Column header text |
type | string | Column type: 'string', 'number', 'boolean', 'date', 'select' |
width | string | Column width (e.g., "120", "100px", "20%") |
min-width | number | Minimum column width in pixels |
sortable | boolean | Enable sorting (presence = true) |
resizable | boolean | Enable resizing (presence = true) |
editable | boolean | Enable editing (presence = true, requires EditingPlugin) |
options | string | Select options: "value1:Label1,value2:Label2" or "val1,val2" |
renderer | string | Named renderer (for framework adapter lookup) |
editor | string | Named editor (for framework adapter lookup) |
<tbw-grid> <tbw-grid-column field="id" header="ID" type="number" width="80"></tbw-grid-column> <tbw-grid-column field="name" header="Name" sortable resizable></tbw-grid-column> <tbw-grid-column field="role" type="select" options="admin:Admin,user:User"></tbw-grid-column></tbw-grid><tbw-grid-column-view>
Section titled “<tbw-grid-column-view>”Custom view template inside a column. Content is used as the cell renderer.
<tbw-grid-column field="status"> <tbw-grid-column-view> <span class="badge">{{ value }}</span> </tbw-grid-column-view></tbw-grid-column><tbw-grid-column-editor>
Section titled “<tbw-grid-column-editor>”Custom editor template inside a column (requires EditingPlugin).
<tbw-grid-column field="name" editable> <tbw-grid-column-editor> <input type="text" /> </tbw-grid-column-editor></tbw-grid-column><tbw-grid-column-header>
Section titled “<tbw-grid-column-header>”Custom header template inside a column.
<tbw-grid-column field="status"> <tbw-grid-column-header> <strong>Status</strong> <span class="required">*</span> </tbw-grid-column-header></tbw-grid-column>Shell Elements
Section titled “Shell Elements”<tbw-grid-header>
Section titled “<tbw-grid-header>”Configure the shell header bar.
| Attribute | Type | Description |
|---|---|---|
title | string | Grid title (left side) |
<tbw-grid> <tbw-grid-header title="Employee Directory"> <tbw-grid-header-content> <span>20 employees</span> </tbw-grid-header-content> </tbw-grid-header></tbw-grid><tbw-grid-header-content>
Section titled “<tbw-grid-header-content>”Custom content in the shell header center area. Must be nested inside <tbw-grid-header>.
<tbw-grid-header title="My Grid"> <tbw-grid-header-content> <input type="search" placeholder="Search..." /> </tbw-grid-header-content></tbw-grid-header><tbw-grid-tool-buttons>
Section titled “<tbw-grid-tool-buttons>”Container for toolbar buttons (right side of shell header).
<tbw-grid> <tbw-grid-tool-buttons> <button class="tbw-toolbar-btn" title="Export">📥</button> <button class="tbw-toolbar-btn" title="Print">🖨️</button> </tbw-grid-tool-buttons></tbw-grid>Tool Panel Elements
Section titled “Tool Panel Elements”<tbw-grid-tool-panel>
Section titled “<tbw-grid-tool-panel>”Define a custom tool panel for the sidebar.
| Attribute | Type | Description |
|---|---|---|
id | string | Required. Unique panel identifier |
title | string | Required. Panel title in accordion header |
icon | string | Icon for accordion header (emoji or text) |
tooltip | string | Tooltip for accordion header |
order | number | Panel order priority (lower = first, default: 100) |
<tbw-grid> <tbw-grid-tool-panel id="filters" title="Filters" icon="🔍" order="10"> <div class="filter-panel"> <label>Status: <select>...</select></label> </div> </tbw-grid-tool-panel></tbw-grid>Plugin-Specific Elements
Section titled “Plugin-Specific Elements”<tbw-grid-detail> (MasterDetailPlugin)
Section titled “<tbw-grid-detail> (MasterDetailPlugin)”Define the detail panel template for master-detail rows. Requires the MasterDetailPlugin.
| Attribute | Type | Description |
|---|---|---|
animation | 'slide' | 'fade' | 'false' | Panel expand/collapse animation (default: 'slide') |
show-expand-column | boolean | Show expand/collapse column (default: true) |
expand-on-row-click | boolean | Expand when row clicked (default: false) |
collapse-on-click-outside | boolean | Collapse when clicking outside (default: false) |
height | number | 'auto' | Panel height in pixels or auto (default: 'auto') |
<tbw-grid> <tbw-grid-detail animation="slide" expand-on-row-click="true"> <div class="detail-panel"> <h3>{{ row.name }}</h3> <p>{{ row.description }}</p> </div> </tbw-grid-detail></tbw-grid>See the MasterDetailPlugin documentation for more details.
<tbw-grid-responsive-card> (ResponsivePlugin)
Section titled “<tbw-grid-responsive-card> (ResponsivePlugin)”Define a custom card template for responsive mode. Requires the ResponsivePlugin.
| Attribute | Type | Description |
|---|---|---|
breakpoint | number | Width threshold in pixels for responsive mode |
card-row-height | number | 'auto' | Card height in pixels or auto (default: 'auto') |
hidden-columns | string | Comma-separated field names to hide in card mode |
hide-header | boolean | Hide header row in responsive mode (default: true) |
debounce-ms | number | Resize debounce delay in ms (default: 100) |
<tbw-grid> <tbw-grid-responsive-card breakpoint="500" card-row-height="80" hidden-columns="createdAt, updatedAt"> <div class="custom-card"> <strong>{{ row.name }}</strong> <span>{{ row.email }}</span> </div> </tbw-grid-responsive-card></tbw-grid>See the ResponsivePlugin documentation for more details.
Helper Functions
Section titled “Helper Functions”import { createGrid, queryGrid } from '@toolbox-web/grid';
// Create a new grid element with configurationconst grid = createGrid<Employee>({ columns: [{ field: 'name' }, { field: 'email' }], fitMode: 'stretch',});document.body.appendChild(grid);grid.rows = employees;
// Query an existing grid with type safetyconst existingGrid = queryGrid<Employee>('#my-grid');if (existingGrid) { existingGrid.rows = newData;}Methods
Section titled “Methods”Data Methods
Section titled “Data Methods”// Update row datagrid.rows = newData;
// Wait for grid to be readyawait grid.ready();
// Force layout recalculationawait grid.forceLayout();
// Get current configuration (readonly)const config = await grid.getConfig();Row Update API
Section titled “Row Update API”The Row Update API provides ID-based access to individual rows for reading and updating data. This is especially useful when you need to update rows after external changes (e.g., API responses, WebSocket events) without replacing the entire dataset.
Row Identification
Section titled “Row Identification”The grid automatically determines row IDs using these sources (in order of precedence):
getRowIdfunction in gridConfig (custom ID resolution)idproperty on the row object_idproperty on the row object
// Configure custom row ID resolutiongrid.gridConfig = { columns: [...], getRowId: (row) => row.employeeId, // Use a custom field as ID};
// Get a row's IDconst id = grid.getRowId(row);console.log(id); // "EMP-123"Reading Rows
Section titled “Reading Rows”// Get a single row by its IDconst employee = grid.getRow('EMP-123');if (employee) { console.log(employee.name);}
// Returns undefined if the row is not foundconst missing = grid.getRow('unknown-id');console.log(missing); // undefinedUpdating Rows
Section titled “Updating Rows”// Update a single row by IDgrid.updateRow('EMP-123', { status: 'active', salary: 75000 });
// Batch update multiple rowsgrid.updateRows([ { id: 'EMP-123', changes: { status: 'active' } }, { id: 'EMP-456', changes: { department: 'Engineering' } },]);
// Specify the update source (default: 'api')// Valid sources: 'user' | 'cascade' | 'api'grid.updateRow('EMP-123', { status: 'inactive' }, 'api');grid.updateRows(updates, 'api');Listening to Row Updates
Section titled “Listening to Row Updates”The cell-change event fires whenever row data is updated via the Row Update API:
grid.on('cell-change', ({ rowId, changes, source, row }) => { console.log(`Row ${rowId} updated via ${source}:`); console.log('Changes:', changes); // { status: 'active' } console.log('Full row:', row); // Complete row object after update});Column Methods
Section titled “Column Methods”// Get all columns with visibility infoconst columns = grid.getAllColumns();// Returns: Array<{ field, header, visible, lockVisible? }>
// Show/hide columnsgrid.setColumnVisible('fieldName', false);grid.toggleColumnVisibility('fieldName');grid.showAllColumns();
// Check column visibilityconst isVisible = grid.isColumnVisible('fieldName');
// Reorder columnsgrid.setColumnOrder(['id', 'name', 'email']);const order = grid.getColumnOrder();Editing Methods
Section titled “Editing Methods”// Start bulk/row editing programmaticallyawait grid.beginBulkEdit(rowIndex);
// Commit active row editawait grid.commitActiveRowEdit();
// Cancel active row editawait grid.cancelActiveRowEdit();
// Get pending changes (array of changed rows)const changes = grid.changedRows;
// Get IDs of changed rows (requires getRowId)const ids = grid.changedRowIds;
// Reset changed rows trackingawait grid.resetChangedRows();Plugin Methods
Section titled “Plugin Methods”| Method | Returns | Description |
|---|---|---|
getPluginByName(name) | Plugin | undefined | Get plugin instance by name — preferred (type-safe, no import needed) |
getPlugin(PluginClass) | P | undefined | Get plugin instance by class (requires import) |
getPluginByName is type-safe for all built-in plugins via the PluginNameMap interface — TypeScript automatically returns the correct plugin type (e.g., SelectionPlugin for 'selection').
// Preferred — type-safe, no import neededconst selection = grid.getPluginByName('selection');selection?.selectAll(); // ✅ SelectionPlugin methods are available
// Alternative — get by class (requires plugin import)import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';const sel = grid.getPlugin(SelectionPlugin);
// Check if plugin is registeredif (selection) { selection.selectAll();}Custom Styles API
Section titled “Custom Styles API”The grid uses light DOM — standard CSS targeting elements inside <tbw-grid> works normally (global stylesheets, <style> in <head>, external CSS files).
For programmatic runtime styles, use registerStyles() which injects CSS via adoptedStyleSheets:
// Inject styles programmatically at runtimegrid.registerStyles('my-id', '.my-class { color: blue; }');
// Remove when no longer neededgrid.unregisterStyles('my-id');Insert & Remove Rows
Section titled “Insert & Remove Rows”When you set rows, the grid automatically re-applies all active processing — sorting, filtering, grouping — so the data stays consistent. This is the right behavior for data refreshes (e.g., API responses), but not for manual row insertion or removal where you want the new row to stay exactly where you placed it.
insertRow(index, row) and removeRow(index) operate directly on the current view without running the plugin pipeline. The row is also added to / removed from the source data so that the next full pipeline run includes it correctly.
Both methods auto-animate by default ('insert' / 'remove' animation). Pass false as the last argument to skip animation. They return Promises that resolve when the animation completes.
// Insert a row at visible index 3 (auto-animates)grid.insertRow(3, newEmployee);
// Insert without animationgrid.insertRow(3, newEmployee, false);// Remove with fade-out animation (default) — await to ensure removalawait grid.removeRow(5);
// Remove immediately, no animationawait grid.removeRow(5, false);Row Animation API
Section titled “Row Animation API”All animation methods return Promises that resolve when the animation completes.
import type { RowAnimationType } from '@toolbox-web/grid';
// Animate a single row by index (await to know when done)await grid.animateRow(rowIndex, 'change'); // 'insert' | 'change' | 'remove'
// Animate a row by its IDawait grid.animateRowById('EMP-123', 'insert');
// Animate multiple rows at onceawait grid.animateRows([0, 1, 2], 'change');Loading States
Section titled “Loading States”// Grid-level loadinggrid.loading = true;grid.loading = { message: 'Loading data...' };grid.loading = { renderer: (container) => { container.textContent = 'Custom...'; } };
// Row-level loading (by row ID, not index)grid.setRowLoading('emp-123', true);grid.setRowLoading('emp-123', false);
// Cell-level loading (by row ID and field name)grid.setCellLoading('emp-123', 'email', true);grid.setCellLoading('emp-123', 'email', false);Column State Persistence
Section titled “Column State Persistence”// Get current column state (for saving)const state = grid.getColumnState();localStorage.setItem('gridState', JSON.stringify(state));
// Restore column stateconst saved = localStorage.getItem('gridState');if (saved) { grid.columnState = JSON.parse(saved);}
// Reset to initial configurationgrid.resetColumnState();Shell Methods (Header/Toolbar)
Section titled “Shell Methods (Header/Toolbar)”// Register a tool panelgrid.registerToolPanel({ id: 'myPanel', title: 'My Panel', icon: '⚙️', render: (container) => { container.innerHTML = '<div>Panel content</div>'; },});
// Open/close/toggle the tool panel sidebargrid.openToolPanel();grid.closeToolPanel();grid.toggleToolPanel();
// Toggle specific accordion sectionsgrid.toggleToolPanelSection('myPanel');
// Check panel stateconst isOpen = grid.isToolPanelOpen;const sections = grid.expandedToolPanelSections;
// Get registered panelsconst panels = grid.getToolPanels();Header & Toolbar Content
Section titled “Header & Toolbar Content”Register custom content in the grid’s header bar (above column headers) or toolbar area:
// Register header content (e.g., a search box)grid.registerHeaderContent({ id: 'global-search', order: 10, render: (container) => { const input = document.createElement('input'); input.type = 'search'; input.placeholder = 'Search all columns...'; container.appendChild(input); },});
// Unregister header contentgrid.unregisterHeaderContent('global-search');
// Get all registered header content definitionsconst headerContents = grid.getHeaderContents();
// Register toolbar content (e.g., action buttons)grid.registerToolbarContent({ id: 'export-buttons', order: 100, render: (container) => { const btn = document.createElement('button'); btn.textContent = 'Export CSV'; btn.className = 'tbw-toolbar-btn'; container.appendChild(btn); },});
// Unregister toolbar contentgrid.unregisterToolbarContent('export-buttons');
// Get all registered toolbar content definitionsconst toolbarContents = grid.getToolbarContents();Custom Styles
Section titled “Custom Styles”// Inject styles programmatically at runtime (uses adoptedStyleSheets)grid.registerStyles('my-styles', '.my-class { color: blue; }');
// Remove when no longer neededgrid.unregisterStyles('my-styles');
// Get list of registered custom style IDsconst styleIds = grid.getRegisteredStyles();Row Height
Section titled “Row Height”// Get the default row height in pixels// For fixed heights: the configured or CSS-measured row height// For variable heights: the average/estimated row heightconst height = grid.defaultRowHeight;Focus Management
Section titled “Focus Management”When building custom editors that render outside the grid DOM (overlays, datepickers, dropdowns appended to <body>), use the focus container registry so the grid treats focus inside those elements as “still in the grid”.
// Register an overlay panel so focus moving into it doesn't close the editorconst panel = document.createElement('div');document.body.appendChild(panel);grid.registerExternalFocusContainer(panel);
// When the overlay is torn down, unregister itgrid.unregisterExternalFocusContainer(panel);
// Check whether focus is logically inside the grid (own DOM + external containers)const hasFocus = grid.containsFocus(); // checks document.activeElementconst nodeInGrid = grid.containsFocus(someNode); // checks specific nodeFocus & Navigation API
Section titled “Focus & Navigation API”Programmatic cell focus and scroll-to-row:
// Focus a cell by column index or field namegrid.focusCell(0, 2); // row 0, column index 2grid.focusCell(5, 'email'); // row 5, field 'email'
// Read the currently focused cellconst cell = grid.focusedCell;if (cell) { console.log(`Row ${cell.rowIndex}, field "${cell.field}"`);}
// Scroll a row into view (no-op if already visible)grid.scrollToRow(42);
// Center the row with smooth scrollinggrid.scrollToRow(42, { align: 'center', behavior: 'smooth' });
// Scroll by row ID (requires getRowId or id/_id property)grid.scrollToRowById('emp-42', { align: 'center' });ScrollToRowOptions:
| Option | Type | Default | Description |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'nearest' | 'nearest' | Where to position the row |
behavior | 'instant' | 'smooth' | 'instant' | Scroll animation |
Events
Section titled “Events”The grid dispatches standard CustomEvents that bubble up the DOM. All events use bubbles: true and composed: true.
import '@toolbox-web/grid';import { queryGrid } from '@toolbox-web/grid';
const grid = queryGrid('tbw-grid')!;
const logEl = document.querySelector<HTMLElement>('[data-event-log]')!;let count = 0;
grid.columns = [ { field: 'id', header: 'ID', width: 60 }, { field: 'name', header: 'Name', width: 150 }, { field: 'role', header: 'Role', width: 130 }, { field: 'score', header: 'Score', type: 'number', width: 80 },];grid.sortable = true;grid.resizable = true;
grid.rows = [ { id: 1, name: 'Alice', role: 'Engineer', score: 92 }, { id: 2, name: 'Bob', role: 'Designer', score: 78 }, { id: 3, name: 'Carol', role: 'Manager', score: 85 }, { id: 4, name: 'Dan', role: 'Engineer', score: 64 }, { id: 5, name: 'Eve', role: 'Designer', score: 91 },];
function logEvent(name: string, detail: unknown) { count++; const entry = document.createElement('div'); entry.style.cssText = 'padding:2px 0;border-bottom:1px solid var(--sl-color-gray-5);'; const summary = typeof detail === 'object' && detail ? JSON.stringify(detail).slice(0, 120) : String(detail); entry.innerHTML = `<span style="color:var(--sl-color-accent)">${count}.</span> <strong>${name}</strong> — ${summary}`; logEl.appendChild(entry); logEl.scrollTop = logEl.scrollHeight;}
const events = ['cell-click', 'row-click', 'cell-activate', 'sort-change', 'column-resize', 'column-state-change', 'data-change'];for (const name of events) { grid.on(name, (detail: unknown) => logEvent(name, detail));}
document.querySelector('[data-clear-log]')!.addEventListener('click', () => { logEl.innerHTML = ''; count = 0;});<div style="display:flex; gap:8px; margin-bottom:8px; align-items:center;"> <span style="font-size:0.85em; color:var(--sl-color-gray-4);">Click cells, sort columns, resize columns to see events.</span> <button data-clear-log style="margin-left:auto; font-size:0.8em;">🗑️ Clear Log</button></div><tbw-grid style="height: 220px;"></tbw-grid><div data-event-log style="max-height:160px; overflow:auto; font-size:0.78em; margin-top:8px; padding:8px; background:var(--sl-color-gray-6); border-radius:4px; font-family:monospace;"></div>Listening to Events
Section titled “Listening to Events”import { queryGrid } from '@toolbox-web/grid';
const grid = queryGrid<Employee>('#my-grid');
// Type-safe event listeninggrid.on('cell-click', ({ row, field }) => { console.log(row, field);});
// Cancelable events — call preventDefault() to reject the actiongrid.on('cell-commit', (detail, e) => { if (!isValid(detail.value)) { e.preventDefault(); // Rejects the edit }});import { DataGrid, useGrid, useGridEvent } from '@toolbox-web/grid-react';import type { CellClickDetail, CellCommitDetail } from '@toolbox-web/grid';
function EmployeeGrid() { const gridRef = useGrid<Employee>();
// Type-safe event hook useGridEvent(gridRef, 'cell-click', (e) => { console.log(e.detail.row, e.detail.field); });
// Or use event handler props const handleCellCommit = useCallback((detail: CellCommitDetail<Employee>) => { if (!isValid(detail.value)) { // Cancelable — return false or call e.preventDefault() } }, []);
return <DataGrid ref={gridRef} rows={employees} onCellCommit={handleCellCommit} />;}<script setup lang="ts">import { TbwGrid } from '@toolbox-web/grid-vue';import type { CellClickDetail, CellCommitDetail } from '@toolbox-web/grid';
function onCellClick(detail: CellClickDetail) { console.log(detail.row, detail.field);}
function onCellCommit(detail: CellCommitDetail) { if (!isValid(detail.value)) { // Cancelable — call detail.preventDefault() }}</script>
<template> <TbwGrid :rows="employees" @cell-click="onCellClick" @cell-commit="onCellCommit" /></template>import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';import { Grid } from '@toolbox-web/grid-angular';
@Component({ imports: [Grid], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <tbw-grid [rows]="employees" (cell-click)="onCellClick($event)" (cell-commit)="onCellCommit($event)" /> `,})export class EmployeeGridComponent { onCellClick(event: CustomEvent) { console.log(event.detail.row, event.detail.field); }
onCellCommit(event: CustomEvent) { if (!isValid(event.detail.value)) { event.preventDefault(); // Rejects the edit } }}Cancelable Events
Section titled “Cancelable Events”Four events support preventDefault() to reject the action:
| Event | Plugin | What Canceling Does |
|---|---|---|
cell-commit | Editing | Reverts the cell to its previous value |
row-commit | Editing | Reverts the entire row to pre-edit state |
column-move | Reorder | Rejects the column drag-and-drop |
row-move | Row Reorder | Rejects the row drag/keyboard move |
Event Reference
Section titled “Event Reference”The DataGridEventMap is the complete, auto-generated reference for every event the grid dispatches — core events and plugin events alike. It includes detail payload types, descriptions, and code examples, grouped by plugin.
CSS Custom Properties
Section titled “CSS Custom Properties”See the Theming page for the complete list of CSS custom properties.
Quick Reference
Section titled “Quick Reference”tbw-grid { /* Colors */ --tbw-color-bg: #ffffff; --tbw-color-fg: #333333; --tbw-color-border: #e0e0e0; --tbw-color-accent: #1976d2;
/* Header */ --tbw-color-header-bg: #f5f5f5; --tbw-color-header-fg: #333333;
/* Rows */ --tbw-color-row-hover: #f0f7ff; --tbw-color-selection: #e3f2fd;
/* Sizing (em-based for proportional scaling) */ --tbw-row-height: 1.75em; --tbw-header-height: 1.875em;}Configuration Patterns
Section titled “Configuration Patterns”Dynamic Styling
Section titled “Dynamic Styling”rowClass — Row-Level CSS Classes
Section titled “rowClass — Row-Level CSS Classes”Apply dynamic CSS classes to entire rows based on row data:
import type { GridConfig } from '@toolbox-web/grid';
const config: GridConfig<Employee> = { rowClass: (row) => { const classes: string[] = []; if (!row.active) classes.push('row-inactive'); if (row.priority === 'high') classes.push('row-priority'); if (row.role === 'admin') classes.push('row-admin'); return classes; },};cellClass — Cell-Level CSS Classes
Section titled “cellClass — Cell-Level CSS Classes”Apply dynamic CSS classes to individual cells:
import type { ColumnConfig } from '@toolbox-web/grid';
const columns: ColumnConfig<Employee>[] = [ { field: 'score', header: 'Score', cellClass: (value, row, column) => { if (value < 30) return ['score-low']; if (value > 70) return ['score-high']; return ['score-medium']; }, }, { field: 'status', header: 'Status', cellClass: (value) => [`status-${value}`], // e.g., 'status-active', 'status-pending' },];Notes:
- Both callbacks return
string[](array of class names) - Empty array
[]means no dynamic classes - Classes are automatically cleaned up when data changes
- Errors in callbacks are caught and logged (rendering continues)
Type-Level Defaults
Section titled “Type-Level Defaults”Define formatters, renderers, and editors at the type level, applying to all columns with matching type.
const config: GridConfig<Employee> = { typeDefaults: { // Formatter — transforms value to display string currency: { format: (value) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }).format(value as number), }, // Renderer — creates custom DOM country: { renderer: (ctx) => { const span = document.createElement('span'); span.textContent = `🌍 ${ctx.value}`; return span; }, }, }, columns: [ { field: 'salary', type: 'currency' }, // Uses currency formatter { field: 'country', type: 'country' }, // Uses country renderer ],};Resolution Priority: Column-level → Grid typeDefaults → App-level (framework adapter) → Built-in
Animation Configuration
Section titled “Animation Configuration”Configure grid-level animation behavior.
| Mode | Behavior |
|---|---|
true / 'on' | Animations always enabled |
false / 'off' | Animations always disabled |
'reduced-motion' | Respects prefers-reduced-motion media query (default) |
grid.gridConfig = { animation: { mode: 'on', duration: 300, easing: 'ease-in-out', }, plugins: [ new ReorderPlugin({ animation: 'flip' }), // 'flip' | 'fade' | false new MasterDetailPlugin({ animation: 'slide' }), // 'slide' | 'fade' | false new TreePlugin({ animation: 'fade' }), // 'slide' | 'fade' | false ],};Animation timing is exposed via CSS:
tbw-grid { --tbw-animation-duration: 200ms; --tbw-animation-easing: ease-out; --tbw-animation-enabled: 1; /* 0 = disabled, 1 = enabled */}Shell Configuration
Section titled “Shell Configuration”Configure the grid’s header bar and tool panel.
grid.gridConfig = { shell: { header: { title: 'Employee Directory', }, toolPanel: { position: 'right', // 'left' | 'right' width: 280, // Panel width in pixels defaultOpen: 'filters', // Panel ID to open initially persistState: true, // Persist open/closed state closeOnClickOutside: true, // Close when clicking outside panel }, },};Icon Customization
Section titled “Icon Customization”Override any grid icon with SVG strings or emoji.
grid.gridConfig = { icons: { sortAsc: '↑', sortDesc: '↓', expand: '+', collapse: '−', },};Accessibility
Section titled “Accessibility”The grid follows the W3C WAI-ARIA Grid Pattern and includes built-in accessibility features.
ARIA Labels
Section titled “ARIA Labels”Provide accessible names for screen reader users:
grid.gridConfig = { gridAriaLabel: 'Employee directory', gridAriaDescribedBy: 'grid-description', // ID of element with description};If gridAriaLabel is not set but shell.header.title is configured, the title is used automatically as the accessible name.
Built-in ARIA Attributes
Section titled “Built-in ARIA Attributes”The grid automatically provides:
role="grid"on the data containerrole="row"androle="gridcell"on rows and cellsrole="columnheader"on header cellsaria-rowcountandaria-colcountfor total countsaria-rowindexandaria-colindexon each cellaria-sorton sortable headersaria-selectedon focused/selected cellsaria-readonlyon non-editable cells (when EditingPlugin is active)aria-checkedon boolean cells
Keyboard Shortcuts
Section titled “Keyboard Shortcuts”See the full keyboard shortcut reference in the Accessibility guide.
Browser Support
Section titled “Browser Support”The grid uses standard Web Components APIs and is compatible with:
- Chrome/Edge 79+
- Firefox 63+
- Safari 13.1+
No polyfills required for modern browsers.
Related Documentation
Section titled “Related Documentation”- Core Features — Detailed guide on columns, renderers, formatters, and shell components
- Theming — Complete CSS custom property reference and theme customization
- Getting Started — Installation and quick start guide
- Demos — Full-featured demo applications
- Angular Adapter —
@toolbox-web/grid-angular - React Adapter —
@toolbox-web/grid-react - Vue Adapter —
@toolbox-web/grid-vue