VanillaGrid
April 30, 2026 · View on GitHub
A tiny dependency‑free data grid with:
- Sort, filter (text/RegExp), pagination, group‑by (sum/min/max)
- Tree (hierarchical) rows with lazy loading
- Remote/server‑side paging, sorting, filtering
- Export to CSV/Markdown and Markdown table ingestion
- Column visibility menu and checkbox row selection
- Built-in settings panel to switch themes (light, dark-blue, dark-grey, midnight, forest, ocean, sand), toggle compact density, and enable striped rows on the fly
- TypeScript support with full type definitions
Quick start
Serve locally, then open in a browser:
npm install
npm start
# then visit http://127.0.0.1:8000/
Tip: Opening demo.html directly works for most features, but the Markdown loader uses fetch(), which requires serving via HTTP.
Build
Requires Node.js and npm.
npm install
npm run build
Outputs to dist/:
dist/vanillagrid.esm.js- ES Module bundledist/vanillagrid.umd.js- UMD bundle (browser global)dist/vanillagrid.min.js- Minified UMD bundledist/vanillagrid.d.ts- TypeScript type definitionsdist/vanillagrid.min.css- Minified stylesdist/vg-pivot-d3.min.js- Pivot chart plugindist/vg-pivot-d3.min.css- Pivot chart styles
dist/ is generated output and is not committed to the main branch. The CI workflow builds it and publishes the generated assets through the gh-pages branch.
CI / GitHub Pages
On every push to main (and via manual workflow_dispatch), GitHub Actions now:
- installs dependencies with
npm ci - builds
dist/withnpm run build - uploads
dist/as a workflow artifact (vanillagrid-dist) - prepares a Pages bundle with the demos + built assets
- publishes that bundle to the
gh-pagesbranch
The published Pages root uses demo.html as index.html, so the demo site opens directly from GitHub Pages.
Installation
Browser (UMD)
Include the minified assets in your page:
<link rel="stylesheet" href="dist/vanillagrid.min.css" />
<script src="dist/vanillagrid.min.js"></script>
<!-- Optional: pivot chart plugin (lazy-loads d3.js on demand) -->
<link rel="stylesheet" href="dist/vg-pivot-d3.min.css" />
<script src="dist/vg-pivot-d3.min.js"></script>
Then instantiate:
const grid = new VanillaGrid('#el', { data, columns });
ES Module
import VanillaGrid from './dist/vanillagrid.esm.js';
const grid = new VanillaGrid('#el', { data, columns });
TypeScript
import VanillaGrid, { VanillaGridOptions, VGColumn } from './dist/vanillagrid.esm.js';
interface MyRow {
id: number;
name: string;
price: number;
}
const options: VanillaGridOptions<MyRow> = {
data: [
{ id: 1, name: 'Item 1', price: 10.50 },
{ id: 2, name: 'Item 2', price: 20.00 }
],
columns: [
{ key: 'id', label: 'ID', type: 'number' },
{ key: 'name', label: 'Name', sortable: true },
{ key: 'price', label: 'Price', type: 'number', sortable: true }
]
};
const grid = new VanillaGrid<MyRow>('#el', options);
Usage Examples
Selection + Columns menu
const grid = new VanillaGrid('#el', {
data,
selectable: true,
columnsMenu: true,
columns: [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'price', label: 'Price', type: 'number', sortable: true },
],
onSelectionChange: rows => console.log('Selected', rows.length)
});
Tree/Hierarchical Data
const grid = new VanillaGrid('#el', {
data: hierarchicalData,
columns: [
{ key: 'name', label: 'Name' },
{ key: 'value', label: 'Value' }
],
tree: {
enabled: true,
childrenKey: 'children',
indent: 20,
initiallyExpanded: false
}
});
Server-side Pagination
const grid = new VanillaGrid('#el', {
data: [],
columns,
serverPagination: true,
serverSorting: true,
serverFiltering: true,
loadPage: async ({ page, pageSize, sortKey, sortDir, filter }) => {
const response = await fetch(`/api/data?page=${page}&size=${pageSize}`);
const { rows, total } = await response.json();
return { rows, total };
}
});
Options Reference
columns: Array of column definitions{ key, label, type, sortable, filterable, format, render, aggregations, link, image, button }selectable: Adds a checkbox column and exposesgetSelectedRows()/clearSelection()columnsMenu: Shows a Columns menu in the toolbar to toggle visibilitytree:{ enabled, childrenKey, indent, lazy, initiallyExpanded, hasChildrenKey }serverPagination|serverSorting|serverFiltering: Enable withloadPage(params)exporting:{ enabled, formats:['csv','md'], scope:'page'|'all', filename }resizableColumns: Enable column resizing by dragging borderseditableRows: Enable inline row editingkeyboardNavigation: Enable arrow key navigationcontextMenu: Enable right-click context menupivotMode: Enable pivot table builder
See demo.html for comprehensive examples including basic grids, tree data, remote data, Markdown ingestion, pivot tables, and all advanced features.
API
See TypeScript definitions for complete API documentation.
Key methods:
setData(data)- Replace grid datasetColumns(columns)- Replace column definitions at runtime (preserves data, sort, filter, pagination)getData()- Get current datasetFilter(text, options)- Apply filtersetSort(key, direction)- Apply sortingsetGroupBy(key)- Group by columnrefresh()- Re-render the grid (toolbar, header, body, pager) without changing statedownloadCSV(filename)- Export to CSVdownloadMarkdown(filename)- Export to MarkdowngetSelectedRows()- Get selected rows (when selectable: true)clearSelection()- Clear row selectiondestroy()/dispose()- Detach event handlers and restore the original container
Run Locally
Serve the repo root (auto-routes to demo.html):
npm start
# custom: npm start -- --port 8080 --host 0.0.0.0
Development
The library is written in TypeScript and compiled to JavaScript:
- Source:
src/vanillagrid.ts - Build system: Rollup with TypeScript plugin
- Output formats: ESM, UMD, minified UMD, and TypeScript definitions
To modify the library:
- Edit
src/vanillagrid.ts - Run
npm run buildto compile - Test with
npm startand opendemo.html
License
MIT