@toolbox-web/grid
v0.3.1
Published
High-performance data grid web component
Downloads
1,964
Maintainers
Readme
@toolbox-web/grid
A high-performance, framework-agnostic data grid built with pure TypeScript and native Web Components. Zero runtime dependencies.
Installation
npm install @toolbox-web/gridQuick Start
import '@toolbox-web/grid';
const grid = document.createElement('tbw-grid');
grid.columns = [
{ field: 'name', header: 'Name' },
{ field: 'email', header: 'Email' },
];
grid.rows = data;
document.body.appendChild(grid);[!TIP] For complete examples, see the Storybook documentation.
Configuration
The grid supports multiple configuration methods, all converging into a single source of truth (effectiveConfig).
Configuration Methods
1. Via gridConfig (recommended for complex setups):
grid.gridConfig = {
columns: [{ field: 'name' }, { field: 'age', type: 'number' }],
fitMode: 'stretch',
editOn: 'dblClick',
plugins: [new SelectionPlugin({ mode: 'row' })],
shell: { header: { title: 'My Data Grid' } },
};2. Via individual properties (convenience for simple cases):
grid.columns = [{ field: 'name' }, { field: 'age' }];
grid.fitMode = 'stretch';
grid.editOn = 'dblClick';3. Via Light DOM (declarative HTML):
<tbw-grid>
<tbw-grid-column field="name" header="Name" sortable></tbw-grid-column>
<tbw-grid-column field="age" header="Age" type="number"></tbw-grid-column>
<tbw-grid-header title="My Data Grid">
<tbw-grid-header-content>
<span>Custom content</span>
</tbw-grid-header-content>
</tbw-grid-header>
</tbw-grid>Precedence
When the same property is set via multiple methods, higher precedence wins:
- Individual props (
fitMode,editOn) - highest columnsprop- Light DOM elements
gridConfigproperty - lowest
Features
API Reference
Element
<tbw-grid></tbw-grid>HTML Attributes
The grid supports configuration via HTML attributes with JSON-serialized values:
| Attribute | Type | Description |
| ------------- | ------ | ------------------------------------------- |
| rows | JSON | Data array (JSON-serialized) |
| columns | JSON | Column definitions (JSON-serialized) |
| grid-config | JSON | Full configuration object (JSON-serialized) |
| fit-mode | string | Column sizing: 'stretch' or 'fixed' |
| edit-on | string | Edit trigger: 'click' or 'dblClick' |
Example with HTML attributes:
<tbw-grid
rows='[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]'
columns='[{"field":"id","header":"ID"},{"field":"name","header":"Name"}]'
fit-mode="stretch"
edit-on="dblClick"
>
</tbw-grid>Properties
| Property | Type | Description |
| ------------ | -------------------------------- | ------------------------------------------------------------------------ |
| rows | T[] | Data array |
| sourceRows | T[] (readonly) | Original unfiltered/unprocessed rows |
| columns | ColumnConfig[] | Column definitions (→ gridConfig.columns) |
| gridConfig | GridConfig | Full configuration object (single source of truth) |
| fitMode | 'stretch' \| 'fixed' | Column sizing behavior (→ gridConfig.fitMode) |
| editOn | 'click' \| 'dblClick' \| false | Edit trigger (→ gridConfig.editOn). Set to false to disable editing. |
Methods
| Method | Returns | Description |
| ---------------------------------- | --------------------- | -------------------------------------- |
| ready() | Promise<void> | Resolves when fully initialized |
| forceLayout() | Promise<void> | Force re-layout |
| getConfig() | Promise<GridConfig> | Get effective configuration |
| resetChangedRows(silent?) | Promise<void> | Clear change tracking |
| beginBulkEdit(rowIndex) | Promise<void> | Start row editing |
| commitActiveRowEdit() | Promise<void> | Commit current edit |
| setColumnVisible(field, visible) | boolean | Set column visibility |
| setColumnOrder(order) | void | Reorder columns by field array |
| getAllColumns() | ColumnInfo[] | Get all columns with visibility status |
| getPlugin(PluginClass) | P \| undefined | Get plugin instance by class |
| getPluginByName(name) | Plugin \| undefined | Get plugin instance by name |
Events
| Event | Detail | Description |
| ----------------------- | --------------------------- | ----------------------------- |
| cell-commit | CellCommitDetail | Cell value committed |
| row-commit | RowCommitDetail | Row edit committed |
| changed-rows-reset | ChangedRowsResetDetail | Change tracking cleared |
| sort-change | SortChangeDetail | Sort state changed |
| column-resize | ColumnResizeDetail | Column resized |
| column-state-change | ColumnState | Column state changed |
| activate-cell | ActivateCellDetail | Cell activated |
| group-toggle | GroupToggleDetail | Row group expanded/collapsed |
| mount-external-view | ExternalMountViewDetail | External view mount request |
| mount-external-editor | ExternalMountEditorDetail | External editor mount request |
Import event names from the DGEvents constant:
import { DGEvents } from '@toolbox-web/grid';
grid.addEventListener(DGEvents.CELL_COMMIT, handler);Column Configuration
interface ColumnConfig {
field: string; // Required: property key in row data
header?: string; // Display label (defaults to field name)
type?: 'string' | 'number' | 'date' | 'boolean' | 'select';
width?: number | string; // Pixels, '1fr', or percentage
sortable?: boolean; // Enable sorting (default: true)
resizable?: boolean; // Enable resize (default: true)
editable?: boolean; // Enable editing
hidden?: boolean; // Initially hidden
lockVisible?: boolean; // Prevent hiding
format?: (value: any, row: T) => string;
}Plugin-Provided Column Properties
Some column properties are added via TypeScript module augmentation when you import a plugin:
| Property | Plugin | Description |
| ------------- | ----------------- | ------------------------ |
| sticky | pinnedColumns | Pin column left or right |
| group | groupingColumns | Column header group |
| filterable | filtering | Enable column filter |
| filterType | filtering | Filter type |
| reorderable | reorder | Enable column reordering |
See Storybook for complete configuration examples.
Grid Configuration
interface GridConfig {
columns?: ColumnConfig[];
fitMode?: 'stretch' | 'fixed';
editOn?: 'click' | 'dblClick' | false;
plugins?: BaseGridPlugin[]; // Array of plugin class instances
icons?: GridIcons; // Centralized icon configuration
shell?: ShellConfig; // Optional header bar and tool panels
}Icons Configuration
The grid provides a centralized icon system via gridConfig.icons. All plugins (tree, grouping, sorting, context menus, etc.) automatically use these icons, ensuring visual consistency across the entire grid.
import { DEFAULT_GRID_ICONS } from '@toolbox-web/grid';
grid.gridConfig = {
icons: {
expand: '▶', // Collapsed tree/group/detail icon
collapse: '▼', // Expanded tree/group/detail icon
sortAsc: '▲', // Sort ascending indicator
sortDesc: '▼', // Sort descending indicator
sortNone: '⇅', // Unsorted column indicator
submenuArrow: '▶', // Context menu submenu arrow
dragHandle: '⋮⋮', // Column reorder drag handle
},
};Icons can be strings (text or HTML) or HTMLElement instances. Plugins use grid-level icons by default but can override with their own config when needed.
Plugin Configuration Example
Plugins are class instances that you import and instantiate with their configuration:
import { GroupingRowsPlugin } from '@toolbox-web/grid/plugins/grouping-rows';
import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';
grid.gridConfig = {
plugins: [
new GroupingRowsPlugin({
groupOn: (row) => row.category,
fullWidth: false,
aggregators: { total: 'sum' },
}),
new SelectionPlugin({
mode: 'row',
multiple: true,
}),
],
};Theming
Apply a built-in theme:
@import '@toolbox-web/grid/themes/dg-theme-standard.css';Available themes: standard, contrast, vibrant, large, bootstrap, material
Custom Theming
Override CSS custom properties on tbw-grid or a parent element:
tbw-grid {
--tbw-color-bg: #ffffff;
--tbw-color-fg: #1a1a1a;
--tbw-color-border: #e5e5e5;
--tbw-color-header-bg: #f5f5f5;
--tbw-row-height: 32px;
}For a complete list of available CSS variables, see grid.css.
Core CSS Variables
| Variable | Description |
| ----------------------- | ---------------------------- |
| --tbw-color-bg | Grid background |
| --tbw-color-fg | Text color |
| --tbw-color-fg-muted | Secondary text color |
| --tbw-color-accent | Accent/primary color |
| --tbw-color-border | Border color |
| --tbw-color-header-bg | Header background |
| --tbw-color-header-fg | Header text color |
| --tbw-color-selection | Selected cell/row background |
| --tbw-color-row-hover | Row hover background |
| --tbw-row-height | Data row height |
| --tbw-header-height | Header row height |
| --tbw-font-family | Font family |
| --tbw-font-size | Base font size |
| --tbw-border-radius | Corner radius |
| --tbw-focus-outline | Focus ring style |
Plugin CSS Variables
Plugins define their own CSS variables following a layered fallback pattern:
var(--tbw-{plugin}-{property}, var(--tbw-{global-property}))This allows you to:
- Override a specific plugin's style:
--tbw-selection-bg - Or let it inherit from the global variable:
--tbw-color-selection
Example: Customizing the selection plugin
tbw-grid {
/* Override just the selection plugin's background */
--tbw-selection-bg: #e0f2fe;
/* Or change the global selection color (affects all plugins) */
--tbw-color-selection: #e0f2fe;
}Common plugin variables:
| Plugin | Variables |
| ------------- | ---------------------------------------------------------- |
| selection | --tbw-selection-bg, --tbw-selection-border |
| filtering | --tbw-filtering-panel-bg, --tbw-filtering-input-border |
| contextMenu | --tbw-context-menu-bg, --tbw-context-menu-hover |
| pinnedRows | --tbw-pinned-rows-bg, --tbw-pinned-rows-border |
| tree | --tbw-tree-indent, --tbw-tree-toggle-color |
Check each plugin's styles property for the full list of customizable variables.
Plugins
The grid uses a plugin architecture for optional features. Each plugin has its own documentation:
| Plugin | Description | Documentation | | --------------------- | ------------------------------ | ----------------------------------------------------------- | | Selection | Cell, row, and range selection | README | | Multi-Sort | Multi-column sorting | README | | Filtering | Column filters | README | | Row Grouping | Row grouping with aggregation | README | | Column Grouping | Column header groups | README | | Tree | Tree/hierarchical data | README | | Pivot | Pivot table transformation | README | | Master-Detail | Expandable detail rows | README | | Pinned Columns | Sticky columns | README | | Reorder | Column drag reordering | README | | Visibility | Column visibility UI | README | | Clipboard | Copy/paste | README | | Context Menu | Right-click menus | README | | Export | CSV/Excel/JSON export | README | | Undo/Redo | Edit history | README | | Server-Side | Lazy data loading | README | | Pinned Rows | Footer aggregations | README | | Column Virtualization | Horizontal virtualization | README |
Creating Custom Plugins
Plugins extend the BaseGridPlugin class:
import { BaseGridPlugin } from '@toolbox-web/grid';
interface MyPluginConfig {
myOption?: boolean;
}
export class MyPlugin extends BaseGridPlugin<MyPluginConfig> {
readonly name = 'myPlugin';
readonly version = '1.0.0';
// CSS injected into shadow DOM
readonly styles = `
.my-element { color: red; }
`;
// Default config (override in constructor)
protected get defaultConfig(): Partial<MyPluginConfig> {
return { myOption: true };
}
// Called when plugin is attached to grid
attach(grid: GridElement): void {
super.attach(grid);
// Setup event listeners, etc.
}
// Called when plugin is detached
detach(): void {
// Cleanup
}
// Hook: Called after grid renders
afterRender(): void {
// DOM manipulation
}
}Inter-Plugin Communication
Plugins can communicate with each other using the generic query system. This allows plugins to expose capabilities or constraints without the core knowing about specific plugin concepts.
Responding to queries (in your plugin):
import { BaseGridPlugin, PLUGIN_QUERIES, PluginQuery } from '@toolbox-web/grid';
export class MyPlugin extends BaseGridPlugin<MyConfig> {
override onPluginQuery(query: PluginQuery): unknown {
switch (query.type) {
case PLUGIN_QUERIES.CAN_MOVE_COLUMN:
// Veto column movement for locked columns
const column = query.context as ColumnConfig;
if (this.isLocked(column)) return false;
return undefined; // Let other plugins decide
default:
return undefined;
}
}
}Querying other plugins:
import { PLUGIN_QUERIES } from '@toolbox-web/grid';
// In your plugin or application code
const responses = grid.queryPlugins<boolean>({
type: PLUGIN_QUERIES.CAN_MOVE_COLUMN,
context: column,
});
const canMove = !responses.includes(false);Built-in query types:
| Query Type | Context | Response | Description |
| ------------------------ | ------------------- | ------------------- | ------------------------------- |
| CAN_MOVE_COLUMN | ColumnConfig | boolean | Can the column be reordered? |
| GET_CONTEXT_MENU_ITEMS | ContextMenuParams | ContextMenuItem[] | Get menu items for context menu |
Plugins can also define custom query types for their own inter-plugin communication.
Accessing Plugin Instances
Use grid.getPlugin() to get a plugin instance for inter-plugin communication or API access:
import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';
const selection = grid.getPlugin(SelectionPlugin);
if (selection) {
selection.selectAll();
}TypeScript
All types are exported from the package:
import type { GridConfig, ColumnConfig, CellCommitDetail, BaseGridPlugin } from '@toolbox-web/grid';Plugin Type Exports
Each plugin exports its class and configuration types from its own entry point:
import { SelectionPlugin, SelectionConfig } from '@toolbox-web/grid/plugins/selection';
import { FilteringPlugin, FilterConfig, FilterModel } from '@toolbox-web/grid/plugins/filtering';
import { TreePlugin, TreeConfig, TreeState } from '@toolbox-web/grid/plugins/tree';All-in-One Bundle
For convenience, you can import everything from the all-in-one bundle:
import {
SelectionPlugin,
FilteringPlugin,
TreePlugin,
// ... all other plugins
} from '@toolbox-web/grid/all';Note: This includes all plugins in your bundle. For smaller bundles, import plugins individually.
Browser Support
Modern browsers with Web Components support (Chrome, Firefox, Safari, Edge).
Development
bun nx build grid # Build
bun nx test grid # Test
bun nx test grid --coverage # Test with coverage
bun nx storybook storybook-app # Storybook (port 4400)For architecture details, rendering pipeline, and plugin development, see ARCHITECTURE.md.
Support This Project
This grid is built and maintained by a single developer in spare time. If it saves you time or money, consider sponsoring to keep development going:
What sponsorship enables:
- 🚀 Faster feature development (see ROADMAP)
- 🐛 Priority bug fixes and support
- 📚 Better documentation and examples
- 💼 Corporate sponsors get logo placement and priority support
License
MIT
