Table

A high-performance table component with virtualization, sorting, filtering, and column management

Installation

Terminal
pnpm add @choice-ui/table

Import

Component.tsx
import { Table, type TableBodyProps, type TableCellProps, type TableColumnProps, type TableEmptyProps, type TableFooterProps, type TableHeaderProps, type TableProps, type TableRowProps, type TableValueProps, type SelectionMode, type ScrollMode, type RowKey, type SortDirection, type SortingState, type SelectionState, type TableColumnDef, type ColumnWidthState, type ColumnWidthsState, type ColumnOrderState, type ResizeState, type TableInstance, type InternalRow, type ConsecutiveStyle, type TableContextValue, type TableProps, type TableHeaderProps, type TableColumnProps, type TableBodyProps, type TableRowProps, type TableCellProps, type TableValueProps, type TableFooterProps, type TableSelectCellProps, useTableStatic, useTableScroll, useTableSelection, useTableColumnState, useTableDragResize, useTableRows, tableVariants } from "@choice-ui/table"

Basic

Basic table with multi-row selection.
**Key Features:**
- Checkbox column for row selection - Shift+Click for range selection - Consecutive selected rows display rounded corners - Header checkbox toggles select all / deselect all
**Usage Tips:**
- Use `selectable` prop to enable selection column - Use `selectionMode="multiple"` for multi-select (default) or `"single"` for single-select - Control selection with `selectedKeys` and `onSelectionChange`
Name
Email
Role
Status

Sortable

Table with sortable columns.
**Key Features:**
- Click header to toggle sort direction (asc → desc → none) - Sort indicator icon shows current direction - Controlled sorting state for server-side sorting support
**Usage Tips:**
- Set `sortable` on Table and individual Columns - Implement your own sorting logic in `onSortingChange` - Works with both client-side and server-side sorting
Name
Email
Role
Department

Resizable And Reorderable

Resizable and reorderable columns.
**Key Features:**
- Drag column edges to resize (guide line shows during drag) - Hold column header 300ms then drag to reorder - Ghost column follows mouse during reorder - Drop indicator shows target position
**Usage Tips:**
- Set `resizable` and/or `reorderable` on Table - Use `minWidth` and `maxWidth` to constrain resize - Control state with `columnWidths` and `columnOrder` props
Order: name → email → role → department
Name
Email
Role
Department

Virtualized

Virtualized table for large datasets.
**Key Features:**
- Efficiently renders 10,000+ rows - Only visible rows are rendered in DOM - Smooth scrolling with configurable overscan - Fixed row height for optimal performance
**Usage Tips:**
- Set `virtualized={true}` (default) for large datasets - Use `rowHeight` prop for fixed row height (default: 32px) - Adjust `overscan` for scroll smoothness (default: 5)
ID
Name
Email
Role
Status

Infinite Scroll

Infinite scroll with server-side data loading simulation.
**Key Features:**
- Loads 100 rows at a time when scrolling near bottom - Loading indicator at bottom during fetch - Simulates 500ms server delay - Stops loading when no more data (max 1000 rows)
**Usage Tips:**
- Use `onScroll` callback to monitor scroll position - Show loading state at bottom while fetching - Implement proper error handling and retry logic - Consider using `useInfiniteQuery` from TanStack Query
Scroll down to load more...
ID
Name
Email
Department
Status

Rich Content

Rich cell content with custom components.
**Key Features:**
- Avatar with user info in single cell - Badge components for tags - Custom row height for complex content
**Usage Tips:**
- Use `rowHeight` prop when cells have taller content - Wrap text content in `Table.Value` for truncation - Complex content doesn't need `Table.Value` wrapper
User
Role
Department
Status

Empty And Loading

Empty and loading states using Table.Empty.
**Key Features:**
- `Table.Empty` component for custom empty/loading content - Replaces `Table.Body` when showing states - Full customization of empty state UI
**Usage Tips:**
- Use conditional rendering: `{isLoading ? <Table.Empty>...</Table.Empty> : <Table.Body>...</Table.Body>}` - Add call-to-action buttons in empty state - Show spinner or skeleton in loading state
Name
Email
Status
Loading data...

Window Scroll

Window scroll mode for full-page layouts.
**Key Features:**
- Table scrolls with browser window - No internal scroll container - Header stays visible when sticky positioned
**Usage Tips:**
- Set `scrollMode="window"` to use window scrolling - Best for full-page table layouts - Open in standalone window for best experience

This component uses window scroll. Open in a standalone window for best experience.

Selected Vs Active

Selected vs Active row states.
**Key Features:**
- **Selected** (solid bg): Rows chosen via checkbox, persists - **Active** (lighter bg): Current focus row, single row only - Keyboard navigation with arrow keys
**Usage Tips:**
- Use `activeRowKey` for keyboard navigation focus - Use `selectedKeys` for user's selection choices - Press Enter/Space to toggle selection on active row
Selected (checkbox checked)
Active (keyboard focus)

Selected: user-2, user-3

Active: user-5

↑↓ to move focus, Enter/Space to toggle selection

ID
Name
Email
Status

Playground

Interactive playground for testing configurations.
**Key Features:**
- Toggle row count, selection mode, virtualization - Live configuration changes - Performance testing with large datasets
**Usage Tips:**
- Test different configurations to find optimal settings - Compare performance with/without virtualization - Try different selection modes
Selected: 0
ID
Name
Email
Role
Status

API reference

TableTypeDefault
data
T[] -
getRowKey
(row: T, index: number) => RowKey -
selectable
boolean
|
undefined
-
selectionMode
undefined
|
"single"
|
"multiple"
|
"none"
-
selectedKeys
RowKey[]
|
undefined
-
defaultSelectedKeys
RowKey[]
|
undefined
-
onSelectionChange
((selectedKeys: RowKey[]) => void)
|
undefined
-
virtualized
boolean
|
undefined
-
rowHeight
number
|
undefined
-
overscan
number
|
undefined
-
scrollMode
undefined
|
"container"
|
"window"
-
scrollRef
RefObject<HTMLElement>
|
undefined
-
containerRef
RefObject<HTMLElement>
|
undefined
-
sortable
boolean
|
undefined
-
sorting
SortingState[]
|
undefined
-
defaultSorting
SortingState[]
|
undefined
-
onSortingChange
((sorting: SortingState[]) => void)
|
undefined
-
resizable
boolean
|
undefined
-
columnWidths
ColumnWidthState
|
undefined
-
defaultColumnWidths
ColumnWidthState
|
undefined
-
onColumnWidthsChange
((widths: ColumnWidthState) => void)
|
undefined
-
reorderable
boolean
|
undefined
-
columnOrder
ColumnOrderState
|
undefined
-
defaultColumnOrder
ColumnOrderState
|
undefined
-
onColumnOrderChange
((order: ColumnOrderState) => void)
|
undefined
-
activeRowKey
RowKey
|
null
|
undefined
-
onRowClick
((row: T, event: MouseEvent<Element, MouseEvent>) => void)
|
undefined
-
className
string
|
undefined
-
height
string
|
number
|
undefined
-
onScroll
((event: { scrollTop: number; scrollHeight: number; clientHeight: number; }) => void)
|
undefined
-
tableRef
RefObject<TableInstance<T>
|
null>
|
undefined
-
children
ReactNode -
tableVariantsTypeDefault
selected
boolean
|
undefined
-
active
boolean
|
undefined
-
sortable
boolean
|
undefined
-
resizing
boolean
|
undefined
-
dragging
boolean
|
undefined
-
class
ClassNameValue -
className
ClassNameValue -