Basic Table with Actions
A standard table with row actions, editable fields, and context menu support. Double-click on descriptions to edit. Grid lines are enabled by default.
Table with Vertical Lines
Enhanced column separation for better data tracking.
Table with Full Grid
Complete grid lines for maximum readability and structure.
Table with Horizontal Lines Only
Emphasis on row separation without column dividers.
Simple Table (No Grid)
Clean, minimal design without grid lines. Set showGrid to false to disable the default grid.
Table with Custom Display Function
Transform data for display using custom formatting.
({
Product: item.product,
'Units Sold': item.units.toLocaleString(),
Revenue: '$' + item.revenue.toLocaleString(),
Growth: (item.growth * 100).toFixed(1) + '%',
'Q1 2024 Forecast': '$' + item.forecast.toLocaleString()
})}
dataName="products"
>
Empty Table State
How the table looks when no data is available.
Schema-First Columns (New)
Defines columns explicitly and renders via schema. No displayFunction needed.
html`${v}` },
{ key: 'joinedAt', header: 'Joined', renderer: (v: string) => new Date(v).toLocaleDateString() },
]}
.data=${[
{ name: 'Alice', email: 'alice@example.com', joinedAt: '2022-08-01' },
{ name: 'Bob', email: 'bob@example.com', joinedAt: '2021-12-11' },
{ name: 'Carol', email: 'carol@example.com', joinedAt: '2023-03-22' },
]}
dataName="users"
>
Partial Schema + Augment (New)
Provides only the important columns; the rest are merged in from displayFunction.
({ name: u.name, email: u.email, role: u.role })}
.augmentFromDisplayFunction=${true}
.data=${[
{ name: 'Erin', email: 'erin@example.com', role: 'Admin' },
{ name: 'Finn', email: 'finn@example.com', role: 'User' },
{ name: 'Gina', email: 'gina@example.com', role: 'User' },
]}
dataName="users"
>
{ console.log('Selection changed', e.detail); }}
@search-changed=${(e: CustomEvent) => {
const tbl = document.getElementById('tableFilterSelectDemo') as any;
if (tbl) tbl.setFilterText(e.detail.value);
}}
@search-submit=${(e: CustomEvent) => {
const tbl = document.getElementById('tableFilterSelectDemo') as any;
if (tbl) tbl.setFilterText(e.detail.value);
}}
>
Filtering + Multi-Selection (New)
Use the search bar to filter rows; toggle selection via checkboxes. Click headers to sort.
Column Filters + Sticky Header (New)
Per-column quick filters and sticky header with internal scroll. Try filtering the Name column. Uses --table-max-height var.
{
const { query } = e.detail || { query: '' };
const table = document.getElementById('serverSearchDemo') as any;
const baseData = [
{ id: 1, name: 'Alice', city: 'Berlin', title: 'Engineer' },
{ id: 2, name: 'Bob', city: 'Paris', title: 'Designer' },
{ id: 3, name: 'Charlie', city: 'London', title: 'Manager' },
{ id: 4, name: 'Diana', city: 'Madrid', title: 'Engineer' },
{ id: 5, name: 'Ethan', city: 'Rome', title: 'Support' },
];
// Simulate async request
await new Promise((r) => setTimeout(r, 300));
const q = String(query || '').toLowerCase();
const filtered = q
? baseData.filter((r) => Object.values(r).some((v) => String(v).toLowerCase().includes(q)))
: baseData;
table.data = filtered;
}}
>
Server Search (New)
Select Server mode, type a query, and watch the table fetch simulated results.
Wide Properties + Many Actions
A table with many columns and rich actions to stress test layout and sticky Actions.
{ console.log('view', item); } },
{ name: 'Edit', iconName: 'lucide:edit', type: ['inRow', 'contextmenu'], actionFunc: async ({ item }) => { console.log('edit', item); } },
{ name: 'Delete', iconName: 'lucide:trash', type: ['inRow', 'contextmenu'], actionFunc: async ({ item }) => { console.log('delete', item); } },
{ name: 'Message', iconName: 'lucide:message-square', type: ['inRow'], actionFunc: async ({ item }) => { console.log('message', item); } },
{ name: 'History', iconName: 'lucide:clock', type: ['inRow'], actionFunc: async ({ item }) => { console.log('history', item); } },
{ name: 'Add New', iconName: 'lucide:plus', type: ['header'], actionFunc: async ({ table }) => { console.log('add'); } },
{ name: 'Export CSV', iconName: 'lucide:download', type: ['header'], actionFunc: async ({ table }) => { console.log('export'); } },
{ name: 'Bulk Delete', iconName: 'lucide:trash-2', type: ['footer'], actionFunc: async ({ table }) => { console.log('bulk delete'); } },
] as ITableAction[]}
>
Scrollable Small Height
Same as above, but with many items and a small fixed height to force vertical scrolling inside the table. Actions remain visible on the right; horizontal scroll appears if needed.
({
id: i + 1,
name: `User ${i + 1}`,
role: ['Engineer','Designer','Manager','QA','Support'][i % 5],
department: ['R&D','Design','Ops','QA','CS'][i % 5],
email: `user${i+1}@corp.com`,
phone: `+1 202 555 ${String(1000 + i).slice(-4)}`,
location: ['Berlin','Paris','London','Madrid','Rome'][i % 5],
status: ['Active','Inactive','On Leave'][i % 3],
createdAt: `2023-${String((i%12)+1).padStart(2,'0')}-${String((i%28)+1).padStart(2,'0')}`,
updatedAt: `2024-${String(((i+3)%12)+1).padStart(2,'0')}-${String(((i+7)%28)+1).padStart(2,'0')}`,
lastLogin: `2024-${String(((i+6)%12)+1).padStart(2,'0')}-${String(((i+10)%28)+1).padStart(2,'0')}`,
projects: (i % 12),
tags: i % 2 ? 'typescript' : 'design',
notes: i % 3 ? '' : 'Note',
}))}
.dataActions=${[
{ name: 'View', iconName: 'lucide:eye', type: ['inRow'], actionFunc: async ({ item }) => {} },
{ name: 'Edit', iconName: 'lucide:edit', type: ['inRow'], actionFunc: async ({ item }) => {} },
{ name: 'Delete', iconName: 'lucide:trash', type: ['inRow'], actionFunc: async ({ item }) => {} },
] as ITableAction[]}
>