Smart Table

A powerful, feature-rich data table with sorting, filtering, pagination, selection, and export capabilities

Quick Start

Get started with Smart Table in under 2 minutes. Simply add the required files and a single data attribute.

1. Include the Files

<!-- CSS --> <link rel="stylesheet" href="styles/smart-table.css"> <!-- JavaScript (at end of body) --> <script src="javascript/smart-table.js"></script>

2. Add the Data Attribute

<table data-rsl-smart-table> <thead> <tr> <th>Name</th> <th>Email</th> <th>Status</th> </tr> </thead> <tbody> <tr> <td>John Smith</td> <td>john@example.com</td> <td>Active</td> </tr> <!-- More rows... --> </tbody> </table>

That's It!

With just data-rsl-smart-table, you get a fully functional table with search, export options, column visibility controls, and pagination. Smart Table uses progressive enhancement - add more attributes to unlock more features.

Features at a Glance

Multi-Column Sorting

Click headers to sort. Hold Shift for multi-column sorting with visual indicators.

Column Filters

Text search or dropdown filters per column. Global search with match highlighting.

Export Data

Export to CSV, JSON, or Excel. Export filtered results or all data.

Row Selection

Checkbox selection with shift-click range selection and bulk actions.

Column Visibility

Toggle column visibility with a dropdown. Respects responsive breakpoints.

Responsive Cards

Automatically converts to card layout on mobile devices.

Sticky Header

Keep headers visible while scrolling through large datasets.

Fully Accessible

ARIA labels, keyboard navigation, screen reader announcements.

Data Attributes Reference

Smart Table is configured entirely through data attributes. Here's the complete reference:

Table Attributes

Apply these to the <table> element:

Attribute Description Default
data-rsl-smart-table Initializes Smart Table. Required. -
data-sortable Enable column sorting (click headers to sort) true
data-filterable Enable column filters below headers false
data-searchable Enable global search in toolbar true
data-selectable Enable row selection with checkboxes false
data-paginated Enable pagination controls true
data-page-size Number of rows per page 10
data-page-sizes Page size options (comma-separated) 10,25,50,100
data-exportable Enable export button in toolbar true
data-export-formats Available export formats (comma-separated) csv,json,excel
data-export-filename Base filename for exports table-export
data-column-toggle Enable column visibility toggle true
data-sticky-header Keep header fixed while scrolling false
data-sticky-offset Offset from top when sticky (e.g., "60px") 0
data-responsive Enable responsive card layout on mobile true
data-responsive-breakpoint Breakpoint for card mode (pixels) 768
data-empty-message Message when no results found No results found
data-loading-message Message during loading state Loading data...
data-server-mode Enable server-side processing mode false

Advanced Feature Attributes

Enable powerful dashboard and editing features:

Attribute Description Default
data-row-actions Enable per-row action buttons (View/Edit/Delete) false
data-row-action-items Which actions to show (comma-separated) view,edit,delete
data-copyable Enable copy to clipboard button false
data-inline-editing Enable double-click to edit cells false
data-editable-columns Which columns can be edited (comma-separated, empty = all) all
data-summary-row Enable summary/totals row at bottom false
data-expandable-rows Enable row expansion with detail panel false
data-expandable-columns Which columns to show in expanded view (comma-separated) all
data-column-resizing Enable drag-to-resize column borders false
data-min-column-width Minimum column width in pixels when resizing 100
data-column-reordering Enable drag-and-drop column reordering false
data-frozen-columns JSON object specifying columns to freeze left/right {"left":[],"right":[]}
data-bulk-actions Enable bulk actions bar when rows selected (requires data-selectable) false
data-bulk-action-items Which bulk actions to show (comma-separated) delete,export
data-bulk-status-options Status options for bulk status change (comma-separated) -
data-saved-views Enable save/load view configurations false
data-view-storage-key localStorage key for saved views (auto-generated if not set) auto
data-full-page-mode Enable full-page toggle button false
data-full-page-padding Padding around table in full-page mode (pixels) 20
data-filter-subscribe Comma-separated FilterBus keys to subscribe to for external filtering status,region,search
data-filter-map Map FilterBus keys to column keys (format: busKey:columnKey) status:statusCol,region:regionCol
data-filter-publish Publish internal filter changes to FilterBus (future) false

Column Attributes

Apply these to <th> elements:

Attribute Description Values
data-type Data type for smart sorting string, number, date, currency, percent
data-sortable Override sorting for this column true, false
data-filter Filter type for this column text, select, none
data-filter-options Options for select filter (comma-separated) Active,Inactive,Pending
data-hidden Initially hide this column true, false
data-priority Column priority (lower = show first) 1, 2, 3...
data-export Include column in exports true, false
data-searchable Include in global search true, false

Cell Attributes

Apply these to <td> elements:

Attribute Description Example
data-sort-value Custom value for sorting (useful for formatted data) data-sort-value="1699900"
data-filter-value Custom value for filtering data-filter-value="active"
data-export-value Custom value for export data-export-value="John Smith"

JavaScript API

For programmatic control, Smart Table provides a comprehensive JavaScript API:

Initialization

Method Description Returns
RSL.SmartTable.init(element, options) Initialize a Smart Table (or call without args to init all) SmartTable instance
RSL.SmartTable.create(element, options) Create a new instance (alias for init) SmartTable instance
RSL.SmartTable.getInstance(element) Get existing instance for element SmartTable instance or null
RSL.SmartTable.destroy(element) Remove Smart Table and restore original table void

Instance Methods

Method Description
sort(column, direction) Sort by column index. Direction: 'asc' or 'desc'
filter(column, value) Filter column by value
search(query) Perform global search
goToPage(page) Navigate to page number
setPageSize(size) Change rows per page
selectRow(index) Select row by index
selectAll() Select all visible rows
deselectAll() Clear all selections
getSelectedRows() Get array of selected row data
export(format, allData) Export data. Format: 'csv', 'json', 'excel'
showColumn(index) Show hidden column
hideColumn(index) Hide visible column
refresh() Re-render the table
getData() Get all table data as array of objects
setData(data) Replace table data programmatically
getTableData() Get complete table state as JSON (headers, rows, config) - ideal for page builder integration
loadData(json) Load table from JSON object (recreates headers and rows from saved state)
copyToClipboard() Copy current table data to clipboard as tab-separated text
getColumnWidths() Get object with current column widths
setColumnWidths(widths) Set column widths from object {colKey: width}
getColumnOrder() Get array of column keys in current order
setColumnOrder(order) Set column order from array of column keys
pinColumn(colKey, side) Pin a column to 'left' or 'right' side
unpinColumn(colKey) Unpin a column from frozen position
saveView(name) Save current view configuration with name
loadView(name) Load a saved view by name
deleteView(name) Delete a saved view
resetView() Reset to default view (clear all customizations)
getSavedViews() Get object of all saved views
toggleFullPage() Toggle full-page mode on/off
isFullPage() Check if currently in full-page mode
destroy() Remove Smart Table and restore original

Configuration Options

Pass an options object to init() or create():

JavaScript Configuration • JS
const table = RSL.SmartTable.create(document.querySelector('table'), {
    // Core Features
    sortable: true,
    filterable: true,
    searchable: true,
    selectable: true,
    paginated: true,
    pageSize: 25,
    pageSizes: [10, 25, 50, 100],
    exportable: true,
    exportFormats: ['csv', 'json', 'excel'],
    exportFilename: 'my-data',
    columnToggle: true,
    stickyHeader: true,
    stickyOffset: '60px',
    responsive: true,
    responsiveBreakpoint: 768,
    emptyMessage: 'No matching records',
    loadingMessage: 'Please wait...',
    serverMode: false,

    // Advanced Features
    rowActions: true,
    rowActionItems: ['view', 'edit', 'delete'],
    copyable: true,
    inlineEditing: true,
    editableColumns: ['Name', 'Email', 'Status'],  // empty array = all columns
    summaryRow: true,
    summaryColumns: [
        { column: 'Amount', type: 'sum', label: 'Total' },
        { column: 'Quantity', type: 'avg', label: 'Average' },
        { column: 'Status', type: 'count', label: 'Count' }
    ],
    expandableRows: true,
    expandableColumns: ['Notes', 'Details', 'History'],
    expandTemplate: function(rowData) {
        return '<div class="custom-detail">' + JSON.stringify(rowData) + '</div>';
    },

    // Quick Filters and Conditional Formatting
    quickFilters: [
        { label: 'Active', column: 'Status', value: 'Active' },
        { label: 'Pending', column: 'Status', value: 'Pending' },
        { label: 'High Value', column: 'Amount', operator: '>', value: 1000 }
    ],
    conditionalFormatting: [
        { column: 'Status', value: 'Active', className: 'status-active' },
        { column: 'Status', value: 'Inactive', className: 'status-inactive' },
        { column: 'Amount', condition: 'gt', value: 5000, className: 'highlight-high' }
    ]
});

Events

Smart Table emits custom events you can listen for:

Event Description Detail Properties
smart-table:sort Fired when sorting changes column, direction, sortState
smart-table:filter Fired when filters change filters, filteredCount
smart-table:search Fired when global search changes query, matchCount
smart-table:page Fired when page changes page, pageSize, totalPages
smart-table:select Fired when selection changes selectedRows, selectedCount
smart-table:export Fired when data is exported format, rowCount
smart-table:column-toggle Fired when column visibility changes column, visible
rsl-smart-table:cell-edit Fired when a cell is edited (inline editing) row, column, oldValue, newValue, rowData
rsl-smart-table:row-expand Fired when a row is expanded row, rowData
rsl-smart-table:row-collapse Fired when a row is collapsed row, rowData
rsl-smart-table:row-action Fired when a row action button is clicked action, row, rowData
rsl-smart-table:column-resize Fired when a column is resized column, width
rsl-smart-table:column-reorder Fired when columns are reordered fromIndex, toIndex, columnOrder
rsl-smart-table:bulk-delete Fired when bulk delete is executed rows, count
rsl-smart-table:bulk-export Fired when bulk export is executed rows, format
rsl-smart-table:bulk-status-change Fired when bulk status change is triggered rows, newStatus
rsl-smart-table:view-saved Fired when a view is saved name, config
rsl-smart-table:view-loaded Fired when a view is loaded name, config
rsl-smart-table:view-deleted Fired when a view is deleted name
rsl-smart-table:view-reset Fired when view is reset to default -
rsl-smart-table:fullpage-toggle Fired when full-page mode is toggled isFullPage
rsl-smart-table:filterbus-update Fired when table is filtered via FilterBus state, meta, instance

Listening to Events

Event Listeners • JS
const table = document.querySelector('[data-rsl-smart-table]');

table.addEventListener('smart-table:sort', (e) => {
    console.log('Sorted by column', e.detail.column, e.detail.direction);
});

table.addEventListener('smart-table:select', (e) => {
    console.log('Selected', e.detail.selectedCount, 'rows');
    // Access selected row data
    console.log(e.detail.selectedRows);
});

table.addEventListener('smart-table:export', (e) => {
    console.log('Exported', e.detail.rowCount, 'rows as', e.detail.format);
});

Advanced Feature Events

Listen for inline editing, row expansion, and row action events:

Advanced Event Listeners • JS
// Inline editing - capture cell changes for saving
table.addEventListener('rsl-smart-table:cell-edit', (e) => {
    console.log('Cell edited:', e.detail);
    // e.detail contains: row, column, oldValue, newValue, rowData

    // Save to server
    fetch('/api/update', {
        method: 'POST',
        body: JSON.stringify({
            row: e.detail.row,
            column: e.detail.column,
            value: e.detail.newValue
        })
    });
});

// Row expansion events
table.addEventListener('rsl-smart-table:row-expand', (e) => {
    console.log('Row expanded:', e.detail.row, e.detail.rowData);
});

table.addEventListener('rsl-smart-table:row-collapse', (e) => {
    console.log('Row collapsed:', e.detail.row);
});

// Row action events (View/Edit/Delete buttons)
table.addEventListener('rsl-smart-table:row-action', (e) => {
    const { action, row, rowData } = e.detail;

    switch(action) {
        case 'view':
            showDetailModal(rowData);
            break;
        case 'edit':
            openEditForm(rowData);
            break;
        case 'delete':
            if (confirm('Delete this row?')) {
                deleteRow(row);
            }
            break;
    }
});

Page Builder JSON API

Smart Table supports full JSON serialization for page builder integration:

JSON Serialization for Page Builders • JS
const instance = RSL.SmartTable.getInstance(table);

// Get complete table state as JSON
const tableJSON = instance.getTableData();
console.log(tableJSON);
// Returns:
// {
//   headers: ['Name', 'Email', 'Status'],
//   rows: [
//     ['John Doe', 'john@example.com', 'Active'],
//     ['Jane Smith', 'jane@example.com', 'Pending']
//   ],
//   config: {
//     sortable: true,
//     filterable: true,
//     // ... all current config options
//   }
// }

// Save to localStorage or server
localStorage.setItem('savedTable', JSON.stringify(tableJSON));

// Load table from saved JSON
const savedData = JSON.parse(localStorage.getItem('savedTable'));
instance.loadData(savedData);

// Use in page builder to recreate table
function buildTableFromConfig(config) {
    const table = document.createElement('table');
    table.setAttribute('data-rsl-smart-table', '');

    // Create headers
    const thead = document.createElement('thead');
    const headerRow = document.createElement('tr');
    config.headers.forEach(header => {
        const th = document.createElement('th');
        th.textContent = header;
        headerRow.appendChild(th);
    });
    thead.appendChild(headerRow);
    table.appendChild(thead);

    // Create body
    const tbody = document.createElement('tbody');
    config.rows.forEach(row => {
        const tr = document.createElement('tr');
        row.forEach(cell => {
            const td = document.createElement('td');
            td.textContent = cell;
            tr.appendChild(td);
        });
        tbody.appendChild(tr);
    });
    table.appendChild(tbody);

    // Initialize with saved config
    return RSL.SmartTable.create(table, config.config);
}

Callback Functions

For server-side processing, use callback functions:

Server Mode Callbacks • JS
const instance = RSL.SmartTable.getInstance(table);

// Server-side sorting
instance.onSortChange = async (sortState) => {
    const data = await fetch(`/api/data?sort=${sortState.column}&dir=${sortState.direction}`);
    instance.setData(await data.json());
};

// Server-side filtering
instance.onFilterChange = async (filters) => {
    const params = new URLSearchParams(filters);
    const data = await fetch(`/api/data?${params}`);
    instance.setData(await data.json());
};

// Server-side pagination
instance.onPageChange = async (page, pageSize) => {
    const data = await fetch(`/api/data?page=${page}&limit=${pageSize}`);
    instance.setData(await data.json());
};

CSS Classes

Smart Table uses BEM-style class naming. Here are the main classes for customization:

Class Description
.rsl-smart-table-wrapper Outer container wrapping everything
.rsl-smart-table-toolbar Top toolbar with search and controls
.rsl-smart-table-search Search input wrapper
.rsl-smart-table-actions Toolbar action buttons container
.rsl-smart-table-container Scrollable table container
.rsl-smart-table The table element itself
.rsl-smart-table-header Column header cell (th)
.rsl-smart-table-sort-icon Sort indicator icon
.rsl-smart-table-filter Column filter input
.rsl-smart-table-row Table row (tr)
.rsl-smart-table-row--selected Selected row state
.rsl-smart-table-checkbox Selection checkbox
.rsl-smart-table-pagination Pagination controls container
.rsl-smart-table-selection-bar Selection count indicator
.rsl-smart-table-empty Empty state message row
.rsl-smart-table-loading Loading overlay

Advanced Feature Classes

Class Description
.rsl-editing Applied to cell currently being edited (inline editing)
.rsl-inline-edit-input The text input field shown during inline editing
.rsl-summary-row The summary/totals row at the bottom of the table
.rsl-summary-cell Individual cell in the summary row
.rsl-summary-label Label text in summary cell (e.g., "Total:")
.rsl-summary-value Calculated value in summary cell
.rsl-expand-col The expand button column header/cell
.rsl-expand-btn The expand/collapse toggle button
.rsl-expanded Applied to expanded row
.rsl-expanded-row The row containing expanded content
.rsl-expanded-content The expanded detail panel container
.rsl-row-actions Container for row action buttons
.rsl-action-btn Individual row action button (View/Edit/Delete)
.rsl-quick-filters Container for quick filter chips
.rsl-quick-filter Individual quick filter chip button
.rsl-quick-filter.active Active state for selected quick filter
.rsl-column-resize-handle Draggable resize handle on column borders
.rsl-resizing Applied to table during column resize
.rsl-reorderable Applied to columns that can be reordered
.rsl-dragging Applied to column being dragged
.rsl-drag-over Applied to column being dragged over
.rsl-frozen-column Applied to frozen/pinned columns
.rsl-frozen-left Applied to left-pinned columns
.rsl-frozen-right Applied to right-pinned columns
.rsl-bulk-actions-bar Bulk actions toolbar when rows selected
.rsl-bulk-action-btn Individual bulk action button
.rsl-bulk-action-danger Danger/delete style for bulk action button
.rsl-saved-views-container Container for saved views buttons
.rsl-saved-view-item Individual saved view item in dropdown
.rsl-full-page-mode Applied to container in full-page mode
.rsl-full-page-btn Full-page toggle button

CSS Custom Properties

Override these variables for theming:

CSS Variables • CSS
:root {
    --rsl-smart-table-bg: #ffffff;
    --rsl-smart-table-border: #e2e8f0;
    --rsl-smart-table-header-bg: #f8fafc;
    --rsl-smart-table-header-text: #1e293b;
    --rsl-smart-table-row-hover: #f1f5f9;
    --rsl-smart-table-row-selected: #eff6ff;
    --rsl-smart-table-primary: #6E7BFF;
    --rsl-smart-table-text: #334155;
    --rsl-smart-table-text-muted: #64748b;
    --rsl-smart-table-radius: 8px;
    --rsl-smart-table-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

Accessibility

Smart Table is built with accessibility in mind:

Keyboard Navigation

Full keyboard support for all interactive elements. Arrow keys for navigation, Enter/Space for activation.

Screen Reader Support

Proper ARIA roles, labels, and live regions for dynamic content announcements.

Focus Management

Visible focus indicators and logical focus order. Focus trapped in dropdowns.

Semantic HTML

Uses proper <table>, <thead>, <tbody> structure.

ARIA Attributes

Attribute Applied To Purpose
aria-sort Column headers Indicates current sort direction
aria-label Buttons, inputs Descriptive labels for screen readers
aria-expanded Dropdown buttons Indicates dropdown state
aria-selected Selectable rows Indicates selection state
aria-live Status messages Announces dynamic updates
role="status" Selection bar Status announcement region

Tip

For the best accessibility, provide meaningful column headers and use data-type attributes to help screen reader users understand data types.

FilterBus Integration

Smart Table can subscribe to the RSL FilterBus for external, shared filtering across multiple components. This is ideal for dashboard scenarios where a single filter control affects multiple data displays.

When to Use FilterBus

Smart Table already has powerful built-in filtering. Use FilterBus when you need:

  • External filter controls (separate from the table)
  • Synchronized filtering across multiple components (tables, charts, KPIs)
  • Shared filter state that persists or can be bookmarked

Basic FilterBus Setup

Connect a Smart Table to the FilterBus using data attributes:

FilterBus Subscription • HTML
<!-- Filter Component publishes to FilterBus -->
<div data-rsl-filter
     data-filter-key="status"
     data-filter-options="All,Active,Pending,Inactive">
</div>

<div data-rsl-filter
     data-filter-key="region"
     data-filter-options="All,North,South,East,West">
</div>

<!-- Smart Table subscribes to FilterBus -->
<table data-rsl-smart-table
       data-filter-subscribe="status,region"
       data-filter-map="status:Status,region:Region">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Status</th>
            <th>Region</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John Smith</td>
            <td>john@example.com</td>
            <td>Active</td>
            <td>North</td>
        </tr>
        <!-- More rows... -->
    </tbody>
</table>

FilterBus Attributes Explained

Attribute Purpose Example
data-filter-subscribe Comma-separated list of FilterBus keys to listen for "status,region,search"
data-filter-map Maps FilterBus keys to column names (busKey:columnName) "status:Status,region:Region"
data-filter-publish Publish internal filter changes back to FilterBus (future feature) true

Special Keys

The following FilterBus keys have special behavior:

Key Behavior
search Applies to global search (same as toolbar search box)
globalSearch Alias for search
Any other key Mapped to column filter via data-filter-map

Listening for FilterBus Updates

When the table is filtered via FilterBus, it emits an event:

FilterBus Event Listener • JS
const table = document.querySelector('[data-rsl-smart-table]');

table.addEventListener('rsl-smart-table:filterbus-update', (e) => {
    console.log('FilterBus state:', e.detail.state);
    console.log('Source:', e.detail.meta.source);
    console.log('Table instance:', e.detail.instance);
});

Dashboard Pattern

Combine Filter components with Smart Tables, KPI Cards, and Charts all subscribed to the same FilterBus keys for a fully synchronized dashboard experience.

Date Range Filtering

Smart Table can filter rows by date range when connected to a Date Picker via FilterBus. Use data-filterbus-date-field to specify which column contains the date to filter by.

Date Range Filter Setup • HTML
<!-- Date Picker publishes date range -->
<input type="text"
       data-rsl-date-picker
       data-mode="range"
       data-show-presets="true"
       data-filterbus-publish="dateFilter">

<!-- Smart Table filters rows by date column -->
<table data-rsl-smart-table
       data-filter-subscribe="dateFilter"
       data-filterbus-date-field="orderDate">
    <thead>
        <tr>
            <th data-col="orderDate" data-type="date">Order Date</th>
            <th data-col="customer">Customer</th>
            <th data-col="amount" data-type="currency">Amount</th>
        </tr>
    </thead>
    <tbody>
        <!-- Rows will be filtered to show only those within selected date range -->
    </tbody>
</table>
Attribute Description
data-filterbus-date-field Column key (from data-col) containing dates to filter. Supports ISO (YYYY-MM-DD), US (MM/DD/YYYY), and European (DD/MM/YYYY) date formats.

Date Format Support

The date column can contain dates in various formats - the Smart Table will automatically parse ISO format (2025-12-03), US format (12/03/2025), and European format (03/12/2025). For best results, use ISO format or mark the column with data-type="date".

Next Steps