Production-ready data table with plugin architecture - Zero dependencies, vanilla JavaScript.
Live Demo β’ Documentation β’ Plugins
- πͺΆ Lightweight - ~32KB minified, zero dependencies
- π Plugin Architecture - Extend with official or custom plugins
- βοΈ Inline Editing - Double-click to edit cells
- π Search & Filter - Global search across all columns
βοΈ Sorting - Multi-column sorting support- π Pagination - Built-in pagination controls
- β Selection - Single/multi row selection with checkboxes
- π± Responsive - Mobile-friendly design
- βΏ Accessible - Keyboard navigation, ARIA labels
- π¨ Themeable - CSS custom properties for styling
npm install @bw-ui/datatableimport { BWDataTable } from '@bw-ui/datatable';
import '@bw-ui/datatable/dist/bw-datatable.min.css';
const table = new BWDataTable('#my-table', {
data: [
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'Editor' },
{ id: 3, name: 'Bob Wilson', email: 'bob@example.com', role: 'Viewer' },
],
});<link
rel="stylesheet"
href="https://unpkg.com/@bw-ui/datatable/dist/bw-datatable.min.css"
/>
<script src="https://unpkg.com/@bw-ui/datatable/dist/bw-datatable.min.js"></script>
<div id="my-table"></div>
<script>
const table = new BWDataTable('#my-table', {
data: [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' },
],
});
</script>new BWDataTable('#table', {
// Data
data: [], // Array of row objects
columns: null, // Column definitions (auto-detect if null)
rowId: 'id', // Field to use as row ID
// Features
editable: false, // Enable inline editing
editableColumns: [], // Which columns are editable
selectable: false, // Enable row selection
selectionMode: 'multi', // 'single' | 'multi' | 'none'
sortable: true, // Enable column sorting
paginated: true, // Enable pagination
pageSize: 20, // Rows per page
searchable: true, // Enable global search
// UI
showHeader: true, // Show table header
showFooter: true, // Show pagination footer
loadingText: 'Loading...', // Loading overlay text
emptyText: 'No data', // Empty state text
// Callbacks
onEditEnd: null, // (rowId, columnId, value, oldValue) => {}
onSelect: null, // (selectedIds) => {}
onSort: null, // (column, direction) => {}
onFilter: null, // (filters) => {}
onPageChange: null, // (page) => {}
});{
columns: [
{
id: 'name', // Unique column ID
header: 'Full Name', // Header text
field: 'name', // Data field (supports dot notation: 'user.name')
type: 'string', // 'string' | 'number' | 'boolean' | 'date'
width: '200px', // Column width
sortable: true, // Enable sorting for this column
editable: true, // Enable editing for this column
hidden: false, // Hide column
render: (value, row) => `<strong>${value}</strong>`, // Custom renderer
},
// ... more columns
],
}const table = new BWDataTable('#table', {
data: myData,
editable: true,
editableColumns: ['name', 'email', 'role'],
onEditEnd: (rowId, columnId, value, oldValue) => {
console.log(`Cell [${rowId}][${columnId}]: ${oldValue} β ${value}`);
// Save to server...
},
});const table = new BWDataTable('#table', {
data: myData,
selectable: true,
selectionMode: 'multi',
onSelect: (selectedIds) => {
console.log('Selected:', selectedIds);
},
});
// Get selected rows
const selected = table.getSelected();const table = new BWDataTable('#table', {
data: myData,
columns: [
{ id: 'name', header: 'Name' },
{ id: 'email', header: 'Email' },
{
id: 'status',
header: 'Status',
render: (value) =>
value
? '<span class="badge green">Active</span>'
: '<span class="badge red">Inactive</span>',
},
{
id: 'salary',
header: 'Salary',
type: 'number',
render: (value) => `$${value.toLocaleString()}`,
},
],
});const table = new BWDataTable('#table', {
data: myData,
searchable: true,
});
// Programmatic filtering
table.filter('global', 'john'); // Search all columns
table.filter('role', 'Admin'); // Filter specific columnconst table = new BWDataTable('#table', {
data: myData,
sortable: true,
onSort: (column, direction) => {
console.log(`Sorted by ${column} ${direction}`);
},
});
// Programmatic sorting
table.sort('name', 'asc');
table.sort('salary', 'desc');Extend functionality with official plugins:
| Package | Description | Size |
|---|---|---|
| @bw-ui/datatable-history | Undo/Redo (Ctrl+Z) | ~3KB |
| @bw-ui/datatable-export | Export JSON, CSV | ~2KB |
| @bw-ui/datatable-url-state | URL sync | ~2KB |
| @bw-ui/datatable-clipboard | Copy/Paste Excel | ~3KB |
import { BWDataTable } from '@bw-ui/datatable';
import { HistoryPlugin } from '@bw-ui/datatable-history';
import { ExportPlugin } from '@bw-ui/datatable-export';
const table = new BWDataTable('#table', { data: myData })
.use(HistoryPlugin)
.use(ExportPlugin);
// Now you have undo/redo and export
table.undo();
table.exportCSV();table.getData(); // Get current rows (filtered/sorted)
table.getOriginalData(); // Get original data
table.setData(newData); // Replace all data
table.addRow(row); // Add single row
table.removeRow(rowId); // Remove row by ID
table.updateRow(rowId, data); // Update row datatable.getSelected(); // Get selected row objects
table.getSelectedIds(); // Get selected row IDs
table.selectAll(); // Select all visible rows
table.clearSelection(); // Clear selectiontable.sort(column, 'asc'); // Sort by column
table.filter('global', term); // Global search
table.filter(column, value); // Column filter
table.clearFilters(); // Clear all filterstable.goToPage(2); // Go to page (0-indexed)
table.setPageSize(50); // Change page sizetable.startEdit(rowId, colId); // Start editing cell
table.setCellValue(rowId, colId, value); // Set cell valuetable.getVisibleColumns(); // Get visible columns
table.hideColumn(colId); // Hide column
table.showColumn(colId); // Show columntable.render(); // Re-render table
table.setLoading(true); // Show loading overlay
table.destroy(); // Cleanup and removeCustomize with CSS custom properties:
:root {
/* Colors */
--bw-dt-bg: #ffffff;
--bw-dt-text: #1a1a1a;
--bw-dt-border: #e5e5e5;
--bw-dt-header-bg: #f8f9fa;
--bw-dt-row-hover: #f5f5f5;
--bw-dt-row-selected: #e3f2fd;
--bw-dt-primary: #2563eb;
/* Spacing */
--bw-dt-cell-padding: 12px 16px;
--bw-dt-border-radius: 8px;
/* Typography */
--bw-dt-font-family: system-ui, sans-serif;
--bw-dt-font-size: 14px;
}[data-theme='dark'] {
--bw-dt-bg: #1a1a1a;
--bw-dt-text: #e5e5e5;
--bw-dt-border: #333333;
--bw-dt-header-bg: #252525;
--bw-dt-row-hover: #2a2a2a;
--bw-dt-row-selected: #1e3a5f;
}| Key | Action |
|---|---|
β β β β |
Navigate cells |
Enter |
Start editing focused cell |
Escape |
Cancel editing |
Tab |
Move to next cell |
Space |
Toggle row selection |
Home / End |
Jump to first/last cell in row |
Ctrl+Home / Ctrl+End |
Jump to first/last row |
dist/
βββ bw-datatable.min.js # IIFE build (for <script>)
βββ bw-datatable.esm.min.js # ESM build (for import)
βββ bw-datatable.min.css # Styles
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
MIT Β© BW UI
Found a bug? Report it here