Components

SortableTable

Sortable data table with generic type safety

Overview

SortableTable is a sortable data table. It provides complete type safety with TypeScript generics.

  • Generic — Define data and field types with <T, F>
  • Sortable — Supports string (localeCompare), number, date, and null
  • Controlled/UncontrolledsortState or defaultSort
  • Accessiblearia-sort attribute, keyboard sorting support

Basic Usage

import { SortableTable } from '@illog/ui'
 
type Task = { id: string; title: string; createdAt: Date; priority: number }
type Field = 'title' | 'createdAt' | 'priority'
 
<SortableTable<Task, Field>
  data={tasks}
  columns={[
    {
      field: 'title',
      header: 'Title',
      render: (task) => <Text>{task.title}</Text>,
    },
    {
      field: 'createdAt',
      header: 'Created',
      render: (task) => <Text>{formatDate(task.createdAt)}</Text>,
      getSortValue: (task) => task.createdAt,
    },
    {
      field: 'priority',
      header: 'Priority',
      render: (task) => <Text>{task.priority}</Text>,
      headerAlign: 'center',
      cellAlign: 'center',
      width: 100,
    },
  ]}
/>

Controlled Sorting

const [sort, setSort] = useState<SortState<Field>>({
  field: 'createdAt',
  direction: 'desc',
})
 
<SortableTable
  data={tasks}
  columns={columns}
  sortState={sort}
  onSortChange={setSort}
/>

Empty State

<SortableTable
  data={[]}
  columns={columns}
  emptyMessage="No tasks found"
/>
 
// Custom empty state
<SortableTable
  data={[]}
  columns={columns}
  emptyState={
    <Center p="800">
      <Stack align="center" gap="300">
        <Icon name="inbox" size="lg" />
        <Text>No data available</Text>
      </Stack>
    </Center>
  }
/>

Column Definition

PropTypeDefaultDescription
fieldFrequiredUnique field key
headerReactNoderequiredHeader content
render(item: T, index: number) => ReactNoderequiredCell renderer
sortablebooleantrueWhether sortable
getSortValue(item: T) => string | number | Date | nullCustom sort value extractor
headerAlign'left' | 'center' | 'right''left'Header alignment
cellAlign'left' | 'center' | 'right''left'Cell alignment
widthstring | numberColumn width

Table Props

PropTypeDefaultDescription
dataT[]requiredData array
columnsSortableTableColumn<T, F>[]requiredColumn definitions
getRowId(item: T, index: number) => stringitem.id || indexRow key
defaultSortSortState<F>Default sort (uncontrolled)
sortStateSortState<F>Sort state (controlled)
onSortChange(sort: SortState<F>) => voidSort change callback
emptyStateReactNodeCustom empty state
emptyMessageReactNode'No data found'Default empty message

Sort Behavior

  • Clicking the same column: toggles ascdesc
  • Clicking a different column: starts with desc
  • Null values are always sorted last
  • Keyboard: toggle sort with Enter/Space

Guidelines

  • Without getSortValue, sorting cannot be applied based on raw data instead of render output
  • Always specify getSortValue for date columns
  • Use sortable: false to exclude columns where sorting is meaningless (e.g., action buttons)