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

PropTypeDefaultDescription
data T[][]Array of data items to display
columns DataTableColumn<T>[][]Column definitions
rowKey string | ((row: T) => string | number)undefinedKey extractor for row identity
selectable booleanfalseEnable row selection
selected Set<string | number>new Set()Set of selected row keys (bindable)
sortable booleanfalseEnable column sorting
sort SortState{ columnId: null, direction: null }Current sort state (bindable)
loading booleanfalseShow loading state
size 'sm' | 'md' | 'lg''md'Table size variant
striped booleanfalseEnable alternating row colors
hoverable booleantrueEnable row hover effect
stickyHeader booleanfalseMake header sticky on scroll
dense booleanfalseCompact 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 scope attributes on headers
  • Keyboard navigation for clickable rows
  • aria-sort for sorted columns
  • Checkbox labels for selection