vanilla-datatable
v1.0.0
Published
A lightweight, zero-dependency DataTable plugin with sorting, filtering, pagination, column toggling, row selection, and CSV export
Maintainers
Readme
vanilla-datatable
A lightweight, zero-dependency DataTable plugin for plain HTML/CSS/JS — inspired by jQuery DataTables but without jQuery.
Features
- Sorting — click any column header, asc/desc toggle
- Global search — instant filtering across all columns
- Per-column filters — text inputs or dropdowns for categorical columns
- Pagination — smart ellipsis page numbers, configurable page size
- Column toggle — show/hide columns via a dropdown
- Column resizing — drag column borders to resize
- Row selection — checkbox selection with select-all and indeterminate state
- CSV export — exports the current filtered/sorted view
- Custom cell renderers — full control over how cells are rendered
- Callbacks —
onSort,onPage,onSearch,onRowClick,onSelectionChange - i18n — all strings are configurable via the
languageoption - TypeScript types — ships with
.d.tsdeclarations
Installation
npm install vanilla-datatableOr via CDN:
<script src="https://unpkg.com/vanilla-datatable/dist/datatable.umd.min.js"></script>Quick Start
<div id="my-table"></div>
<script type="module">
import DataTable from 'vanilla-datatable';
const columns = [
{ key: 'id', label: 'ID', type: 'number' },
{ key: 'name', label: 'Name', type: 'text' },
{ key: 'dept', label: 'Department', type: 'select' },
{ key: 'salary', label: 'Salary', type: 'number',
render: (val) => '$' + val.toLocaleString() },
{ key: 'status', label: 'Status', type: 'select' },
];
const data = [
{ id: 1, name: 'Aria Patel', dept: 'Engineering', salary: 95000, status: 'Active' },
{ id: 2, name: 'Marcus Chen', dept: 'Marketing', salary: 82000, status: 'Active' },
{ id: 3, name: 'Sofia Torres', dept: 'Design', salary: 88000, status: 'Pending' },
// ...
];
const table = new DataTable('#my-table', columns, data, {
pageSize: 10,
rowSelection: true,
onRowClick: (row) => console.log('Clicked:', row),
});
</script>Column Definition
| Property | Type | Description |
|-----------------|-------------------------------|-----------------------------------------------------------|
| key | string | Field name in your data objects |
| label | string | Column header text |
| type | text \| number \| date \| select | Affects sort and auto filter type |
| sortable | boolean | Default true. Set to false to disable |
| filterable | boolean | Default true. Set to false to hide filter input |
| filterOptions | string[] | Force a dropdown filter with these options |
| width | string | Initial column width, e.g. '120px' |
| render | (value, row) => string \| HTMLElement | Custom cell renderer |
Options
new DataTable(container, columns, data, {
pageSize: 10, // rows per page
pageSizeOptions: [5, 10, 25, 50],
sortable: true,
searchable: true,
columnFilters: true,
columnToggle: true,
resizableColumns: true,
rowSelection: false,
exportCSV: true,
language: {
search: 'Search…',
showing: (start, end, total, totalAll) => `${start}–${end} of ${total}`,
noRecords: 'No records found',
rowsPerPage: 'rows',
show: 'Show',
columns: 'Columns',
csv: 'CSV',
selected: (n) => `${n} selected`,
},
onRowClick: (row) => {},
onSelectionChange: (rows) => {},
onSort: (key, dir) => {},
onPage: (page) => {},
onSearch: (query) => {},
});API Methods
const table = new DataTable(/* ... */);
table.setData(newData); // Replace all data
table.addRows([{ id: 99, ... }]); // Append rows
table.removeRow('id', 99); // Delete a row by key=value
table.getSelectedRows(); // Returns selected row objects
table.search('query'); // Programmatic search
table.goToPage(3); // Jump to page
table.sortBy('salary', 'desc'); // Programmatic sort
table.exportCSV('my-export.csv'); // Trigger CSV download
table.toggleColumn('salary', false);// Hide a column
table.destroy(); // Remove the table from DOMCustom Cell Renderer
const columns = [
{
key: 'status',
label: 'Status',
render: (value) => {
const badge = document.createElement('span');
badge.style.cssText = 'padding:2px 8px;border-radius:99px;font-size:11px;font-weight:500;';
badge.style.background = value === 'Active' ? '#e6f4ea' : '#fce8e6';
badge.style.color = value === 'Active' ? '#1e7e34' : '#c62828';
badge.textContent = value;
return badge;
}
}
];Overriding Styles
All classes are prefixed with vdt-. Override them in your own CSS:
/* Custom header background */
table.vdt thead tr { background: #1a1a2e; }
table.vdt th { color: #fff; }
/* Custom active page button */
.vdt-page-btn.vdt-active { background: #e63946; border-color: #e63946; }
/* Custom selected row */
table.vdt tbody tr.vdt-selected { background: #fff3cd; }Browser Support
All modern browsers. No IE11 support (uses ES2015+ classes and template literals).
License
MIT
