DataTable
A flexible, accessible data table component with sorting, row selection, custom cell renderers, and Material 3 styling.
Installation
typescript
import { DataTable } from '@happyvertical/smrt-svelte';Basic Usage
Display data with column definitions.
svelte
<script lang="ts">
import { DataTable } from '@happyvertical/smrt-svelte';
interface User {
id: string;
name: string;
email: string;
}
const users: User[] = [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' }
];
const columns = [
{ id: 'name', label: 'Name' },
{ id: 'email', label: 'Email' }
];
</script>
<DataTable data={users} columns={columns} rowKey="id" />Sortable Columns
Enable sorting on specific columns.
svelte
<script lang="ts">
const columns = [
{ id: 'name', label: 'Name', sortable: true },
{ id: 'email', label: 'Email', sortable: true },
{ id: 'status', label: 'Status' } // Not sortable
];
let sort = $state({ columnId: null, direction: null });
</script>
<DataTable
data={users}
columns={columns}
rowKey="id"
sortable
bind:sort
onSortChange={(newSort) => console.log('Sort:', newSort)}
/>Row Selection
Enable single or multi-select with checkboxes.
svelte
<script lang="ts">
let selected = $state(new Set<string>());
</script>
<DataTable
data={users}
columns={columns}
rowKey="id"
selectable
bind:selected
onSelectionChange={(newSelected) => {
console.log('Selected:', [...newSelected]);
}}
/>Custom Cell Rendering
Use snippets to customize cell content.
typescript
const columns = [
{ id: 'name', label: 'Name' },
{
id: 'status',
label: 'Status',
cell: ({ value }) => {
return value === 'active'
? '<span class="badge-green">Active</span>'
: '<span class="badge-gray">Inactive</span>';
}
}
];Loading and Empty States
Handle loading and empty data gracefully.
svelte
<DataTable
data={loading ? [] : users}
columns={columns}
rowKey="id"
loading={loading}
>
{#snippet empty()}
<div class="empty-state">
<p>No users found</p>
<button>Add User</button>
</div>
{/snippet}
</DataTable>Row Click Handler
Handle row clicks for navigation or details.
svelte
<DataTable
data={users}
columns={columns}
rowKey="id"
onRowClick={(row, index) => {
goto(`/users/${row.id}`);
}}
/>Styling Options
Configure appearance with props.
svelte
<DataTable
data={users}
columns={columns}
rowKey="id"
size="sm"
striped
dense
stickyHeader
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | T[] | [] | Array of data items to display |
columns | DataTableColumn<T>[] | [] | Column definitions |
rowKey | string | ((row: T) => string | number) | undefined | Key extractor for row identity |
selectable | boolean | false | Enable row selection |
selected | Set<string | number> | new Set() | Set of selected row keys (bindable) |
sortable | boolean | false | Enable column sorting |
sort | SortState | { columnId: null, direction: null } | Current sort state (bindable) |
loading | boolean | false | Show loading state |
size | 'sm' | 'md' | 'lg' | 'md' | Table size variant |
striped | boolean | false | Enable alternating row colors |
hoverable | boolean | true | Enable row hover effect |
stickyHeader | boolean | false | Make header sticky on scroll |
dense | boolean | false | Compact padding mode |
TypeScript
typescript
import { DataTable } from '@happyvertical/smrt-svelte';
import type { DataTableColumn, SortState } from '@happyvertical/smrt-svelte';
interface DataTableColumn<T> {
id: string;
label: string;
accessor?: string | keyof T;
sortable?: boolean;
sortFn?: (a: T, b: T, dir: SortDirection) => number;
width?: string;
minWidth?: string;
maxWidth?: string;
align?: 'left' | 'center' | 'right';
hidden?: boolean;
className?: string;
header?: Snippet<[{ column: DataTableColumn<T> }]>;
cell?: Snippet<[{ row: T; value: unknown; index: number }]>;
}
interface SortState {
columnId: string | null;
direction: 'asc' | 'desc' | null;
}Accessibility
- Semantic
<table>structure - Proper
scopeattributes on headers - Keyboard navigation for clickable rows
aria-sortfor sorted columns- Checkbox labels for selection