PowerTable is a powerful JavaScript component that transforms JSON data into fully interactive HTML tables with built-in capabilities for sorting, filtering, searching, and editing data directly in the browser. When integrated with Svelte, it provides a reactive, performant solution for building complex data management interfaces. This guide walks through implementing advanced table features including custom column configurations, real-time filtering, multi-column sorting, and inline cell editing using PowerTable with Svelte. This is part 29 of a series on using PowerTable with Svelte.
Prerequisites
Before starting, ensure you have:
- Node.js version 18 or higher
- SvelteKit 1.0+ or a Svelte project with Vite
- Basic understanding of Svelte reactivity and component lifecycle
- Familiarity with JavaScript arrays and object manipulation
For this advanced tutorial, we'll work with complex data structures and reactive state management. Here's a quick example of what we'll be building:
<!-- Example: PowerTable with reactive data binding -->
<script>
import PowerTable from 'powertable';
let data = $state([...]);
let table = new PowerTable(data, { sortable: true, editable: true });
</script>
Installation
Install PowerTable using npm, pnpm, or yarn:
npm install powertable
Or with pnpm:
pnpm add powertable
Or with yarn:
yarn add powertable
After installation, your package.json should include:
{
"dependencies": {
"powertable": "^1.0.0"
}
}
Project Setup
Create a new Svelte component for your table. First, set up the basic project structure:
src/
├── lib/
│ ├── components/
│ │ └── AdvancedTable.svelte
│ └── utils/
│ └── tableConfig.js
└── App.svelte
Create a configuration utility file for table settings:
// src/lib/utils/tableConfig.js
export const createTableConfig = (options = {}) => {
return {
sortable: options.sortable ?? true,
filterable: options.filterable ?? true,
editable: options.editable ?? true,
searchable: options.searchable ?? true,
pagination: options.pagination ?? { enabled: true, pageSize: 10 },
columns: options.columns ?? [],
...options
};
};
First Example / Basic Usage
Let's start with a simple working example that demonstrates PowerTable's core functionality:
<!-- src/lib/components/AdvancedTable.svelte -->
<script>
import PowerTable from 'powertable';
import { onMount } from 'svelte';
// Sample data
const sampleData = [
{ id: 1, name: 'John Doe', email: 'john@example.com', age: 28, department: 'Engineering' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', age: 32, department: 'Marketing' },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', age: 45, department: 'Sales' },
{ id: 4, name: 'Alice Williams', email: 'alice@example.com', age: 29, department: 'Engineering' },
{ id: 5, name: 'Charlie Brown', email: 'charlie@example.com', age: 38, department: 'HR' }
];
let tableContainer;
let powerTable;
let tableData = $state([...sampleData]);
onMount(() => {
// Initialize PowerTable
powerTable = new PowerTable(tableData, {
sortable: true,
filterable: true,
editable: true,
searchable: true
});
// Render table to container
powerTable.render(tableContainer);
return () => {
// Cleanup
if (powerTable) {
powerTable.destroy();
}
};
});
</script>
<div class="table-container" bind:this={tableContainer}></div>
<style>
.table-container {
width: 100%;
margin: 20px 0;
}
</style>
This creates a basic interactive table with sorting, filtering, searching, and editing capabilities. The table automatically generates columns from your data structure and provides a user-friendly interface for data manipulation.
Understanding the Basics
PowerTable integrates with Svelte through reactive state management. The key concepts are:
- Data Binding: PowerTable works with JavaScript arrays of objects
- Reactive Updates: Changes to your data automatically reflect in the table
- Event Handling: PowerTable emits events for user interactions (edit, sort, filter)
Here's an enhanced example with reactive data binding:
<script>
import PowerTable from 'powertable';
import { onMount } from 'svelte';
let tableContainer;
let powerTable;
let tableData = $state([
{ id: 1, product: 'Laptop', price: 999, stock: 15 },
{ id: 2, product: 'Mouse', price: 25, stock: 100 },
{ id: 3, product: 'Keyboard', price: 75, stock: 50 }
]);
// Reactive update function
function updateTable() {
if (powerTable) {
powerTable.updateData(tableData);
}
}
// Add new row
function addRow() {
tableData = [...tableData, {
id: tableData.length + 1,
product: 'New Product',
price: 0,
stock: 0
}];
updateTable();
}
onMount(() => {
powerTable = new PowerTable(tableData, {
sortable: true,
editable: true,
onEdit: (row, column, value) => {
// Handle edit events
const index = tableData.findIndex(item => item.id === row.id);
if (index !== -1) {
tableData[index][column] = value;
tableData = [...tableData]; // Trigger reactivity
}
}
});
powerTable.render(tableContainer);
return () => powerTable?.destroy();
});
</script>
<button on:click={addRow}>Add Row</button>
<div bind:this={tableContainer}></div>
Practical Example / Building Something Real
Let's build a complete employee management table with advanced features:
<!-- src/lib/components/EmployeeTable.svelte -->
<script>
import PowerTable from 'powertable';
import { onMount } from 'svelte';
import { createTableConfig } from '../utils/tableConfig.js';
export let employees = $state([]);
export let onSave = (data) => {};
let tableContainer;
let powerTable;
let searchTerm = $state('');
let sortConfig = $state({ column: null, direction: 'asc' });
let filterConfig = $state({});
// Column configuration with custom renderers
const columnConfig = [
{
key: 'id',
label: 'ID',
sortable: true,
width: 80
},
{
key: 'name',
label: 'Full Name',
sortable: true,
filterable: true,
editable: true,
width: 200
},
{
key: 'email',
label: 'Email',
sortable: true,
filterable: true,
editable: true,
validator: (value) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}
},
{
key: 'department',
label: 'Department',
sortable: true,
filterable: true,
editable: true,
type: 'select',
options: ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance']
},
{
key: 'salary',
label: 'Salary',
sortable: true,
editable: true,
type: 'number',
formatter: (value) => `$${value.toLocaleString()}`
},
{
key: 'hireDate',
label: 'Hire Date',
sortable: true,
type: 'date',
formatter: (value) => new Date(value).toLocaleDateString()
}
];
// Initialize table
onMount(() => {
const config = createTableConfig({
columns: columnConfig,
sortable: true,
filterable: true,
editable: true,
searchable: true,
pagination: {
enabled: true,
pageSize: 15
},
onEdit: handleEdit,
onSort: handleSort,
onFilter: handleFilter
});
powerTable = new PowerTable(employees, config);
powerTable.render(tableContainer);
// Watch for data changes
$effect(() => {
if (powerTable && employees.length > 0) {
powerTable.updateData(employees);
}
});
return () => powerTable?.destroy();
});
function handleEdit(row, column, newValue) {
const index = employees.findIndex(emp => emp.id === row.id);
if (index !== -1) {
employees[index][column] = newValue;
employees = [...employees]; // Trigger reactivity
onSave(employees);
}
}
function handleSort(column, direction) {
sortConfig = { column, direction };
// Custom sorting logic if needed
powerTable.sort(column, direction);
}
function handleFilter(filters) {
filterConfig = filters;
powerTable.filter(filters);
}
function handleSearch() {
powerTable.search(searchTerm);
}
function exportData() {
const data = powerTable.getData();
const csv = convertToCSV(data);
downloadCSV(csv, 'employees.csv');
}
function convertToCSV(data) {
if (!data.length) return '';
const headers = Object.keys(data[0]).join(',');
const rows = data.map(row => Object.values(row).join(','));
return [headers, ...rows].join('\n');
}
function downloadCSV(content, filename) {
const blob = new Blob([content], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
</script>
<div class="table-controls">
<div class="search-box">
<input
type="text"
placeholder="Search employees..."
bind:value={searchTerm}
on:input={handleSearch}
/>
</div>
<button on:click={exportData} class="export-btn">Export CSV</button>
</div>
<div class="table-wrapper" bind:this={tableContainer}></div>
<style>
.table-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
}
.search-box input {
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
width: 300px;
}
.export-btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.export-btn:hover {
background: #0056b3;
}
.table-wrapper {
width: 100%;
overflow-x: auto;
}
</style>
Usage in your main component:
<!-- src/App.svelte -->
<script>
import EmployeeTable from './lib/components/EmployeeTable.svelte';
let employees = $state([
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
department: 'Engineering',
salary: 95000,
hireDate: '2020-01-15'
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
department: 'Marketing',
salary: 85000,
hireDate: '2019-03-20'
}
// ... more employees
]);
function handleSave(updatedEmployees) {
// Save to backend or update state
console.log('Saving employees:', updatedEmployees);
// API call here
}
</script>
<EmployeeTable {employees} onSave={handleSave} />
Common Issues / Troubleshooting
Issue 1: Table not rendering after data update
Problem: Changes to data array don't reflect in the table.
Solution: Use updateData() method and ensure reactivity:
$effect(() => {
if (powerTable) {
powerTable.updateData(tableData);
}
});
Issue 2: Custom column renderers not working
Problem: Custom formatters or validators aren't applied.
Solution: Ensure column configuration is passed correctly and PowerTable version supports these features:
const columnConfig = [
{
key: 'price',
formatter: (value) => `$${value}`,
validator: (value) => value > 0
}
];
Issue 3: Performance issues with large datasets
Problem: Table becomes slow with thousands of rows.
Solution: Enable pagination and virtual scrolling:
const config = {
pagination: {
enabled: true,
pageSize: 50
},
virtualScrolling: true
};
Issue 4: Edits not persisting
Problem: Cell edits don't save properly.
Solution: Implement proper event handlers and state management:
powerTable = new PowerTable(data, {
editable: true,
onEdit: (row, column, value) => {
// Update your state
updateRow(row.id, column, value);
// Persist to backend
saveToBackend(row.id, { [column]: value });
}
});
Advanced Features
Custom Cell Renderers
Create custom cell content with Svelte components:
<script>
import PowerTable from 'powertable';
const customColumns = [
{
key: 'status',
render: (value, row) => {
const color = value === 'active' ? 'green' : 'red';
return `<span style="color: ${color}">${value}</span>`;
}
},
{
key: 'actions',
render: (value, row) => {
return `
<button onclick="editRow(${row.id})">Edit</button>
<button onclick="deleteRow(${row.id})">Delete</button>
`;
}
}
];
</script>
Real-time Data Synchronization
Sync table data with external sources:
<script>
import { onMount } from 'svelte';
let tableData = $state([]);
// WebSocket or polling for real-time updates
onMount(() => {
const ws = new WebSocket('ws://your-api/table-updates');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
tableData = update.data;
powerTable?.updateData(tableData);
};
return () => ws.close();
});
</script>
Multi-column Sorting
Enable sorting by multiple columns:
const config = {
sortable: true,
multiSort: true,
onSort: (sorts) => {
// sorts is an array of { column, direction }
console.log('Active sorts:', sorts);
}
};
Next Steps
- Explore PowerTable's API documentation for additional configuration options
- Implement server-side pagination and filtering for large datasets
- Add data validation and error handling for user inputs
- Integrate with state management libraries like Svelte stores
- Check out other articles in this series for more PowerTable patterns
Summary
You've learned how to build advanced interactive data tables with PowerTable in Svelte, including custom column configurations, real-time filtering, multi-column sorting, and inline editing. You can now create production-ready data management interfaces with reactive state management, custom validators, and export functionality. The combination of PowerTable's powerful features and Svelte's reactivity provides an excellent foundation for complex data-driven applications.
Top comments (0)