Advanced Data Grid/Table Library in Vanilla JavaScript – VanillaGrid
It takes any tabular data arrays and transforms them into interactive data tables with sorting, filtering, pagination, hierarchical rows, and server-side capabilities.
1. Include the minified CSS and JavaScript files in your HTML.
<link rel="stylesheet" href="dist/vanillagrid.min.css" /> <script src="dist/vanillagrid.min.js"></script>
2. Create a <div> to hold the data grid.
<div id="grid"></div>
3. Prepare your data array:
const products = [
{ id: 1, name: 'Caffè Mocha', price: 3.75, category: 'Drinks', stock: 42 },
{ id: 2, name: 'Espresso', price: 2.10, category: 'Drinks', stock: 90 },
{ id: 3, name: 'Cheese Cake', price: 4.95, category: 'Dessert', stock: 15 },
// ... more data
]; 4. Instantiate VanillaGrid and pass the container’s selector, your data, and a configuration object. The columns array is where you define your table structure.
const grid = new VanillaGrid('#grid', {
data: products,
pageSize: 5,
filterable: true,
columns: [
{ key: 'name', label: 'Name', type: 'text', sortable: true },
{ key: 'category', label: 'Category', type: 'text', sortable: true },
{ key: 'price', label: 'Price', type: 'number', sortable: true },
{ key: 'stock', label: 'In Stock', type: 'number', sortable: true },
{ key: 'action', label: '', type: 'button', button: {
text: 'Add',
onClick: (row) => alert(`Added: ${row.name}`)
}, sortable: false },
],
}); 5. To create a hierarchical tree table, you enable the tree option and provide a loadChildren function for lazy loading.
const categories = [
{ id: 'drinks', name: 'Drinks', hasChildren: true },
{ id: 'food', name: 'Food', hasChildren: true },
{ id: 'dessert', name: 'Dessert', hasChildren: true },
];
const treeGrid = new VanillaGrid('#grid', {
data: categories,
pageSize: 100,
columns: [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'id', label: 'ID', sortable: true },
],
tree: { enabled: true, lazy: true, initiallyExpanded: false },
loadChildren: async (row) => {
// fake async: filter products by category id
await new Promise(r => setTimeout(r, 400));
const list = products.filter(p => p.category.toLowerCase() === row.id);
return list.map(p => ({ id: p.id, name: p.name }));
}
}); 6. For large datasets, you’ll want to handle pagination, sorting, and filtering on the server. VanillaGrid supports this with a few configuration flags and a loadPage function.
// Remote pagination demo (fake server)
const serverData = Array.from({ length: 237 }, (_, i) => ({ id: i+1, name: `Row ${i+1}`, category: i % 2 ? 'A' : 'B' }));
const simulateServer = async ({ page, pageSize, sortKey, sortDir, filter }) => {
await new Promise(r => setTimeout(r, 250));
let rows = serverData.slice();
if (filter) rows = rows.filter(r => Object.values(r).some(v => String(v).toLowerCase().includes(filter.toLowerCase())));
if (sortKey) {
const dir = sortDir === 'desc' ? -1 : 1;
rows.sort((a,b) => dir * String(a[sortKey] ?? '').localeCompare(String(b[sortKey] ?? ''), undefined, { numeric: true }));
}
const total = rows.length;
const start = (page - 1) * pageSize;
rows = rows.slice(start, start + pageSize);
return { rows, total };
};
const remoteGrid = new VanillaGrid('#remote-grid', {
data: [],
pageSize: 10,
columns: [
{ key: 'id', label: 'ID', type: 'number', sortable: true },
{ key: 'name', label: 'Name', sortable: true },
{ key: 'category', label: 'Category', sortable: true },
],
serverPagination: true,
serverSorting: true,
serverFiltering: true,
loadPage: simulateServer,
}); 7. VanillaGrid supports various cell types beyond basic text and numbers:
const advancedColumns = [
{
key: 'img',
label: '',
type: 'image',
image: { alt: 'product', width: 60, height: 40 },
sortable: false
},
{
key: 'url',
label: 'Link',
type: 'link',
link: { text: 'Open' },
sortable: false
},
{
key: 'desc',
label: 'Description',
type: 'html',
sortable: false
},
{
key: 'action',
label: '',
type: 'button',
button: {
text: 'Add',
onClick: (row) => alert(`Added: ${row.name}`)
},
sortable: false
}
]; 8. All available configuration options.
data: (Array<Object>) The array of data objects to display in the grid. Default: [].columns: (Array<Object>) An array of column definition objects. Each object defines a column’s key, label, type, etc.pageSize: (number) The number of rows to show on each page. Default: 10.pageSizes: (Array<number>) An array of page size options for the user to choose from. Default: [10, 25, 50, 100, 1000].sortable: (boolean) Enables or disables sorting for all columns. Can be overridden per column. Default: true.filterable: (boolean) Enables or disables the filter input for the grid. Default: false.pagination: (boolean) Enables or disables the pagination controls. Default: true.groupable: (boolean) Enables or disables the group-by dropdown selector. Default: false.groupBy: (string | null) The key of the column to group the data by initially. Default: null.regexFilter: (boolean) If true, the filter input will be treated as a regular expression. Default: false.className: (string) A custom CSS class to add to the grid’s container element. Default: ''.emptyMessage: (string) The message to display when there are no rows in the data. Default: 'No rows to display.'.tree: (Object) Configuration for tree-grid functionality. Options include enabled, childrenKey, indent, lazy, initiallyExpanded, and hasChildrenKey.loadChildren: (Function) An async function to lazily load child nodes in a tree grid. It receives the parent row and should return an array of child rows.serverPagination: (boolean) If true, pagination is handled by the server. Requires loadPage. Default: false.serverSorting: (boolean) If true, sorting is handled by the server. Requires loadPage. Default: false.serverFiltering: (boolean) If true, filtering is handled by the server. Requires loadPage. Default: false.loadPage: (Function) An async function to fetch a page of data from the server. It receives arguments like page, pageSize, sortKey, etc., and should return an object with { rows, total }.exporting: (Object) Configuration for data export. Options include enabled, formats, scope, and filename.selectable: (boolean) If true, a checkbox column is added to allow row selection. Default: false.onSelectionChange: (Function) A callback function that is executed when the row selection changes. It receives an array of the selected rows.columnsMenu: (boolean | Object) Enables a menu to toggle column visibility. Can be true for defaults or an object for detailed configuration.onColumnsVisibilityChange: (Function) A callback executed when a column’s visibility is changed through the columns menu. It receives a Set of hidden column keys.resizableColumns: (boolean) Allows users to resize columns by dragging their borders. Default: false.editableRows: (boolean) Enables inline row editing. Default: false.rowDragDrop: (boolean) Allows users to reorder rows via drag and drop. Default: false.frozenColumns: (number) The number of columns from the left to freeze in place during horizontal scrolling. Default: 0.keyboardNavigation: (boolean) Enables cell navigation using arrow keys. Default: true.contextMenu: (boolean) Enables a right-click context menu on rows. Default: true.onRowEdit: (Function) A callback executed after a cell is edited. It receives the row, field, newValue, and oldValue.onRowDrop: (Function) A callback executed after a row is dropped. It receives the draggedRow, targetRow, and position ('before' or 'after').customCellTypes: (Object) An object to register custom cell renderers, mapping a typeName to a render function.pivotMode: (boolean) Enables pivot table functionality. Default: false.pivotConfig: (Object) The configuration for the pivot table, including rows, columns, values, and aggregations.onPivotChange: (Function) A callback executed when the pivot table’s data or configuration changes.data: [],
columns: [], // [{ key, label, type, sortable, filterable, format, render, aggregations:['sum','min','max'], link:{text,target}, image:{alt,width,height}, button:{text, onClick} }]
pageSize: 10,
pageSizes: [10, 25, 50, 100, 1000],
sortable: true,
filterable: false,
pagination: true,
groupable: false,
groupBy: null, // key or null
regexFilter: false,
className: '',
emptyMessage: 'No rows to display.',
// i18n strings (override any to localize)
i18n: {
tableLabel: 'Data table',
filterPlaceholder: 'Filter...',
regexLabel: 'RegExp',
invalidRegex: 'Invalid RegExp',
noGroup: 'No group',
groupByPrefix: 'Group by',
perPageSuffix: ' / page',
search: {
simple: 'Simple',
caseSensitive: 'Case-sensitive',
regex: 'RegExp',
treeFilter: 'Tree/Filter'
},
pager: {
pageInfo: (p, t) => `Page ${p} of ${t}`,
prev: 'Previous page',
next: 'Next page',
first: 'First page',
last: 'Last page',
totalRows: n => `${n} row(s)`,
totalGroups: n => `${n} group(s)`,
},
group: { count: 'Count', min: 'min', max: 'max' },
aria: { toggleGroup: 'Toggle group', expandRow: 'Expand', collapseRow: 'Collapse' },
export: { button: 'Export', csv: 'CSV', markdown: 'Markdown', format: 'Format' }
},
// Tree options
tree: {
enabled: false,
childrenKey: 'children',
indent: 16,
lazy: false,
initiallyExpanded: false,
hasChildrenKey: 'hasChildren',
},
loadChildren: null, // async (row) => children array
// Remote/server-side options
serverPagination: false,
serverSorting: false,
serverFiltering: false,
loadPage: null, // async ({page,pageSize,sortKey,sortDir,filter,regexMode}) => { rows, total }
// Export options
exporting: {
enabled: false,
formats: ['csv', 'md'], // supported: 'csv', 'md'
scope: 'page', // 'page' | 'all'
filename: 'vanillagrid'
},
// Selection
selectable: false, // adds a checkbox column and selection API
onSelectionChange: null, // (selectedRows) => void
// Column visibility
// columnsMenu can be:
// - false to disable
// - true for defaults
// - object for configuration: { location:'pager'|'toolbar', label:string, showSearch:boolean, showSelectAll:boolean, include:string[], exclude:string[], persistKey:string, initialHidden:string[] }
columnsMenu: false,
onColumnsVisibilityChange: null, // (hiddenCols:Set<string>) => void
// New features
resizableColumns: false, // allow column resizing by dragging borders
editableRows: false, // enable inline row editing
rowDragDrop: false, // enable row reordering via drag and drop
frozenColumns: 0, // number of columns to freeze on the left
keyboardNavigation: true, // enable arrow key navigation
contextMenu: true, // enable right-click context menu
onRowEdit: null, // (row, field, newValue, oldValue) => void
onRowDrop: null, // (draggedRow, targetRow, position) => void
customCellTypes: {}, // custom cell renderers: { typeName: renderFunction }
// Pivot table options
pivotMode: false, // enable pivot table mode
pivotConfig: {
rows: [], // field names for row grouping
columns: [], // field names for column grouping
values: [], // field names for value aggregation
aggregations: {}, // field -> aggregation function mapping
},
onPivotChange: null, // (pivotData, config) => void 9. API methods.
setData(data): Replaces all data rows in the grid and resets the view to the first page.getData(): Returns a shallow copy of the current data array in the grid.setGroupBy(key): Sets or removes grouping by a specific column key. Pass null or an empty string to remove grouping.setFilter(text, options): Applies a filter to the grid data. Options can specify regexMode and caseSensitive.setSort(key, dir): Sorts the grid by a column key in the specified direction ('asc' or 'desc').setPageSize(size): Sets the number of rows to display per page.setMarkdown(markdown, options): Parses a Markdown string, finds a table, and loads its content into the grid.loadMarkdown(url, fetchOptions): Fetches a Markdown file from a URL and loads its table content into the grid.downloadCSV(filename): Downloads the current grid data as a CSV file.downloadMarkdown(filename): Downloads the current grid data as a Markdown table file.addRow(rowData, index): Adds a new row with the given rowData at the specified index. If index is omitted, the row is added to the end.updateRow(rowId, newData): Updates the data of a row specified by its unique rowId.deleteRow(rowId): Deletes a row from the grid by its unique rowId.setColumnWidth(columnKey, width): Sets the display width of a specific column in pixels.getColumnWidth(columnKey): Retrieves the current width of a specific column.resetColumnWidths(): Resets the widths of all columns to their default values.startEdit(rowId, columnKey): Programmatically begins the editing process for a specific cell.focusCell(rowId, columnKey): Sets the browser focus on a specific cell in the grid.registerCellType(typeName, renderFunction): Registers a new custom cell type with a custom rendering function.unregisterCellType(typeName): Removes a previously registered custom cell type.enablePivot(config): Activates pivot table mode with a given configuration for rows, columns, and values.disablePivot(): Deactivates pivot table mode and restores the grid to its standard table view.updatePivotConfig(config): Updates the configuration of the active pivot table.getPivotData(): Returns the processed data currently displayed in the pivot table.getAvailableFields(): Returns a list of field names available for use in the pivot table configuration.getSelectedRows(): Returns an array containing the data objects of all currently selected rows.clearSelection(): Deselects all currently selected rows in the grid.exportPivotData(): Exports the current pivot table view as a CSV file.clearPivotConfig(): Clears the current pivot table configuration, removing all fields from rows, columns, and values.applyPivotFilters(): Applies the currently defined filters to the pivot table data.removePivotField(type, field): Removes a field from a specific area (rows, columns, etc.) of the pivot configuration.movePivotField(type, field, direction): Changes the position of a field within a specific area of the pivot configuration.The post Advanced Data Grid/Table Library in Vanilla JavaScript – VanillaGrid appeared first on CSS Script.
Spoilers of course follow for The Boys Season 5, Episode 7.With Prime Video's The Boys…
FORT WAYNE, Ind. (WOWO) — After President Trump signaled support for suspending the 18-cent federal…
INDIANAPOLIS, Ind. (WOWO) — Katherine Legge will become the first woman to try and complete…
The U.S. Capitol is pictured on March 3, 2026. (Photo by Jennifer Shutt/States Newsroom)WASHINGTON —…
The U.S. Capitol is pictured on March 3, 2026. (Photo by Jennifer Shutt/States Newsroom)WASHINGTON —…
The U.S. Capitol is pictured on March 3, 2026. (Photo by Jennifer Shutt/States Newsroom)WASHINGTON —…
This website uses cookies.