Advanced Data Grid/Table Library in Vanilla JavaScript – VanillaGrid

VanillaGrid is a lightweight data grid library that creates feature-rich data tables without any external dependencies.

It takes any tabular data arrays and transforms them into interactive data tables with sorting, filtering, pagination, hierarchical rows, and server-side capabilities.

Features:

  • Data manipulation: Sort columns, filter with text or RegExp patterns, paginate large datasets, and group rows with aggregation functions.
  • Hierarchical display: Create tree tables with lazy-loaded children and expandable/collapsible rows.
  • Server integration: Handle remote pagination, sorting, and filtering for large datasets.
  • Export capabilities: Generate CSV and Markdown files from grid data.
  • Interactive elements: Column visibility menu, checkbox selection, resizable columns, and custom context menus.
  • Enhanced cell types: Display progress bars, ratings, color indicators, images, links, and custom buttons.
  • Accessibility: Full keyboard navigation support and ARIA compliance.
  • Pivot Table: Interactive pivot table builder with drag & drop interface

How to use it:

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.


Discover more from RSS Feeds Cloud

Subscribe to get the latest posts sent to your email.

Discover more from RSS Feeds Cloud

Subscribe now to keep reading and get access to the full archive.

Continue reading