DataTable is a feature-rich table component built on TanStack Table that provides sorting, filtering, pagination, row selection, column resizing, and more.
Import
import { DataTable } from 'popui'
Basic Usage
<script lang="ts">
import { DataTable } from 'popui'
type User = {
id: string
name: string
email: string
status: string
}
const data: User[] = [
{ id: '1', name: 'John Doe', email: '[email protected]', status: 'active' },
{ id: '2', name: 'Jane Smith', email: '[email protected]', status: 'inactive' }
]
const columns = [
{
id: 'name',
accessorKey: 'name',
header: 'Name',
cellType: 'text'
},
{
id: 'email',
accessorKey: 'email',
header: 'Email',
cellType: 'text'
},
{
id: 'status',
accessorKey: 'status',
header: 'Status',
cellType: 'tag',
cellConfig: {
options: [
{ value: 'active', label: 'Active', color: 'green' },
{ value: 'inactive', label: 'Inactive', color: 'grey' }
]
}
}
]
</script>
<DataTable {data} {columns} />
Column Types
DataTable supports multiple built-in cell types:
Text Cell
{
id: 'name',
accessorKey: 'name',
header: 'Name',
cellType: 'text',
cellConfig: {
className: 'font-bold'
}
}
Boolean Cell
Display icons based on boolean values:
<script>
import { Check } from '@invopop/ui-icons'
</script>
{
id: 'verified',
accessorKey: 'verified',
header: 'Verified',
cellType: 'boolean',
cellConfig: {
icon: Check,
iconClass: 'size-4 text-green-500',
showWhenTrue: true,
showWhenFalse: false,
hintWhenTrue: 'Verified user',
hintWhenFalse: 'Not verified'
}
}
Tag Cell
Display status tags with colors:
{
id: 'status',
accessorKey: 'status',
header: 'Status',
cellType: 'tag',
cellConfig: {
options: [
{ value: 'active', label: 'Active', color: 'green' },
{ value: 'pending', label: 'Pending', color: 'yellow' },
{ value: 'inactive', label: 'Inactive', color: 'grey' }
],
showDot: true
}
}
Date Cell
{
id: 'createdAt',
accessorKey: 'createdAt',
header: 'Created At',
cellType: 'date',
cellConfig: {
className: 'text-sm'
}
}
Currency Cell
{
id: 'amount',
accessorKey: 'amount',
header: 'Amount',
cellType: 'currency',
cellConfig: {
className: 'font-semibold'
}
}
UUID Cell
{
id: 'id',
accessorKey: 'id',
header: 'ID',
cellType: 'uuid',
cellConfig: {
prefixLength: 4,
suffixLength: 4,
full: false,
disabled: false,
onCopy: (value) => {
console.log('Copied:', value)
}
}
}
Custom Cell Renderer
You can provide custom cell renderers using a function or Snippet:
<script lang="ts">
import { DataTable } from 'popui'
import CustomComponent from './CustomComponent.svelte'
import { renderComponent } from 'popui/data-table'
const columns = [
{
id: 'custom',
accessorKey: 'name',
header: 'Custom',
cell: (value, row) => {
return renderComponent(CustomComponent, { value, data: row })
}
}
]
</script>
Sorting
Enable sorting on columns:
<script lang="ts">
const columns = [
{
id: 'name',
accessorKey: 'name',
header: 'Name',
cellType: 'text',
enableSorting: true // Enable sorting (default: true)
}
]
</script>
<DataTable
{data}
{columns}
initialSortColumn="name"
initialSortDirection="asc"
/>
Manual Sorting (Server-Side)
<script lang="ts">
function handleSortingChange(columnId: string, direction: 'asc' | 'desc' | '') {
// Fetch sorted data from server
console.log('Sort by:', columnId, direction)
}
</script>
<DataTable
{data}
{columns}
manualSorting={true}
onSortingChange={handleSortingChange}
/>
<DataTable
{data}
{columns}
initialPageSize={25}
initialPage={0}
/>
<script lang="ts">
let currentPage = 0
let pageSize = 10
let totalPages = 10
let totalRows = 100
function handlePageChange(pageIndex: number) {
currentPage = pageIndex
// Fetch data for new page
}
function handlePageSizeChange(newPageSize: number) {
pageSize = newPageSize
currentPage = 0
// Fetch data with new page size
}
</script>
<DataTable
{data}
{columns}
manualPagination={true}
pageCount={totalPages}
rowCount={totalRows}
initialPage={currentPage}
initialPageSize={pageSize}
onPageChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
/>
Row Selection
<script lang="ts">
function handleSelectionChange(selectedRows) {
console.log('Selected:', selectedRows)
}
</script>
<DataTable
{data}
{columns}
onSelectionChange={handleSelectionChange}
/>
To disable selection:
<DataTable {data} {columns} disableSelection={true} />
Row Actions
<script lang="ts">
import { Edit, Trash } from '@invopop/ui-icons'
const rowActions = [
{ label: 'Edit', value: 'edit', icon: Edit },
{ label: 'Delete', value: 'delete', icon: Trash, destructive: true }
]
function handleRowAction(action, row) {
console.log('Action:', action, 'Row:', row)
}
</script>
<DataTable
{data}
{columns}
{rowActions}
onRowAction={handleRowAction}
/>
Dynamic Row Actions
<script lang="ts">
function getRowActions(row) {
if (row.status === 'active') {
return [
{ label: 'Deactivate', value: 'deactivate' },
{ label: 'Edit', value: 'edit' }
]
}
return [
{ label: 'Activate', value: 'activate' }
]
}
</script>
<DataTable
{data}
{columns}
{getRowActions}
onRowAction={handleRowAction}
/>
Column Management
Column Visibility
<DataTable
{data}
{columns}
initialColumnVisibility={{
email: false // Hide email column initially
}}
onColumnVisibilityChange={(visibility) => {
console.log('Visibility changed:', visibility)
}}
/>
Column Resizing
<script lang="ts">
const columns = [
{
id: 'name',
accessorKey: 'name',
header: 'Name',
cellType: 'text',
size: 200,
minSize: 100,
maxSize: 400,
enableResizing: true
}
]
</script>
<DataTable
{data}
{columns}
onColumnResize={(sizes) => {
console.log('Column sizes:', sizes)
}}
/>
Frozen Columns
<DataTable
{data}
{columns}
initialFrozenColumns={['name', 'email']}
onFreezeChange={(columnId) => {
console.log('Freeze toggled for:', columnId)
}}
/>
Column Ordering
<DataTable
{data}
{columns}
initialColumnOrder={['status', 'name', 'email']}
onColumnOrderChange={(order) => {
console.log('New column order:', order)
}}
/>
Loading State
Display skeleton placeholders while loading:
<script lang="ts">
import { User } from '@invopop/ui-icons'
const columns = [
{
id: 'name',
accessorKey: 'name',
header: 'Name',
cellType: 'text',
loadingConfig: {
lines: 1,
showAvatar: true,
avatarSize: 32
}
},
{
id: 'email',
accessorKey: 'email',
header: 'Email',
cellType: 'text',
loadingConfig: {
lines: 2
}
}
]
</script>
<DataTable {data} {columns} loading={true} />
Row Styling
<script lang="ts">
function getRowClassName(row) {
return row.status === 'critical' ? 'bg-red-50' : ''
}
function getRowState(row) {
return {
isError: row.status === 'error',
isWarning: row.status === 'warning',
isSuccess: row.status === 'success'
}
}
</script>
<DataTable
{data}
{columns}
{getRowClassName}
{getRowState}
/>
Row Click Handler
<script lang="ts">
function handleRowClick(row) {
console.log('Row clicked:', row)
}
</script>
<DataTable {data} {columns} onRowClick={handleRowClick} />
Empty State
<script lang="ts">
import { Search } from '@invopop/ui-icons'
</script>
<DataTable
{data}
{columns}
emptyState={{
iconSource: Search,
title: 'No users found',
description: 'Try adjusting your search criteria'
}}
/>
Keyboard Navigation
By default, DataTable supports keyboard navigation:
- Arrow Up/Down: Navigate rows
- Shift + Arrow Up/Down: Select multiple rows
- Space/Enter: Select current row
- Escape: Clear focus
To disable keyboard navigation:
<DataTable {data} {columns} disableKeyboardNavigation={true} />
Props
Array of data objects to display in the table.
columns
DataTableColumn<TData>[]
required
Column definitions for the table.
Show skeleton placeholders instead of data.
Disable row selection functionality.
Disable pagination controls.
disableKeyboardNavigation
Disable keyboard navigation.
Disable all controls (filters, pagination, view options).
Disable first/last page buttons and make page input read-only.
Static row actions available for all rows.
getRowActions
(row: TData) => TableAction[]
Function to dynamically generate row actions based on row data.
onRowAction
(action: any, row: TData) => void
Callback when a row action is clicked.
Initial number of rows per page.
Initial page index (0-based).
Initial column ID to sort by.
Array of column IDs to freeze initially.
Initial column order (array of column IDs).
Initial column visibility state.
Initial column sizes (column ID to width in pixels).
Configuration for empty state display.
Callback when a row is clicked.
onSelectionChange
(selectedRows: TData[]) => void
Callback when row selection changes.
Enable server-side pagination mode.
Enable server-side sorting mode.
Total number of pages (for manual pagination).
Total number of rows (for manual pagination).
onPageChange
(pageIndex: number) => void
Callback when page changes.
onPageSizeChange
(pageSize: number) => void
Callback when page size changes.
onSortingChange
(columnId: string, direction: TableSortBy) => void
Callback when sorting changes.
onFilterChange
(columnId: string) => void
Callback when filter changes.
onFreezeChange
(columnId: string) => void
Callback when column freeze state changes.
onColumnResize
(columnSizes: Record<string, number>) => void
Callback when columns are resized.
onColumnOrderChange
(columnOrder: string[]) => void
Callback when column order changes.
onColumnVisibilityChange
(visibility: Record<string, boolean>) => void
Callback when column visibility changes.
Function to generate custom CSS class for rows.
getRowState
(row: TData) => { isSuccess?: boolean; isError?: boolean; isWarning?: boolean }
Function to set row state (affects row styling).
Column Definition
Unique identifier for the column.
Key to access data in the row object.
Header text to display. Use empty string or omit for no header.
cellType
'text' | 'boolean' | 'tag' | 'date' | 'currency' | 'uuid' | 'custom'
Built-in cell renderer type.
Configuration object for the cell renderer (varies by cellType).
Custom cell renderer function or Snippet.
Enable sorting for this column.
Allow this column to be hidden.
Allow this column to be resized.
Disable column filter option.
Default column width in pixels.
Minimum column width in pixels.
Maximum column width in pixels.
Configuration for loading skeleton placeholders.
Cell Config Types
TextCellConfig
Custom CSS class for the cell.
BooleanCellConfig
Show icon when value is true.
Show icon when value is false.
Tooltip text when value is true.
Tooltip text when value is false.
TagCellConfig
options
Array<{ value: string; label: string; color: StatusType }>
required
Tag options mapping values to labels and colors.
Show dot indicator before tag label.
DateCellConfig
Custom CSS class for the cell.
CurrencyCellConfig
Custom CSS class for the cell.
UuidCellConfig
Number of characters from start to show.
Number of characters from end to show.
Disable copy functionality.
Callback when UUID is copied.
Loading Config
Number of skeleton lines to show.
Show skeleton avatar before lines.
Size of skeleton avatar in pixels.