Table
Data table with sorting, filtering, and column resize plugins.
Examples
Section titled “Examples”Default
Section titled “Default”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
<Table columns={columns} data={data} idKey="id" />Empty State
Section titled “Empty State”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
No tasks foundTry adjusting filters or creating a new task. | ||||
<Table columns={columns} data={[]} emptyState={ <EmptyState description="Try adjusting filters or creating a new task." isCompact title="No tasks found" /> }/>Default Empty State
Section titled “Default Empty State”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
No data | ||||
<Table columns={columns} data={[]} />Density
Section titled “Density”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
function DensityStory() { return ( <div style={{display: 'grid', gap: 24}}> <Table columns={columns} data={data.slice(0, 2)} density="compact" /> <Table columns={columns} data={data.slice(0, 2)} density="balanced" /> <Table columns={columns} data={data.slice(0, 2)} density="spacious" /> </div> );}
<DensityStory />Dividers
Section titled “Dividers”| Source | Cost |
|---|---|
| Compute | $18.00 |
| Storage | $6.00 |
| Total | $24.00 |
| Source | Cost |
|---|---|
| Compute | $18.00 |
| Storage | $6.00 |
| Total | $24.00 |
| Source | Cost |
|---|---|
| Compute | $18.00 |
| Storage | $6.00 |
| Total | $24.00 |
| Source | Cost |
|---|---|
| Compute | $18.00 |
| Storage | $6.00 |
| Total | $24.00 |
function DividersStory() { const variants: TableDividers[] = ['rows', 'columns', 'grid', 'none']; return ( <div style={{display: 'grid', gap: 24}}> {variants.map(variant => ( <Table dividers={variant} key={variant} label={`${variant} dividers`}> <TableHeader> <TableRow> <TableHeaderCell>Source</TableHeaderCell> <TableHeaderCell>Cost</TableHeaderCell> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Compute</TableCell> <TableCell>$18.00</TableCell> </TableRow> <TableRow> <TableCell>Storage</TableCell> <TableCell>$6.00</TableCell> </TableRow> </TableBody> <TableFooter> <TableRow> <TableCell>Total</TableCell> <TableCell>$24.00</TableCell> </TableRow> </TableFooter> </Table> ))} </div> );}
<DividersStory />Striped
Section titled “Striped”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
<Table columns={columns} data={data} idKey="id" isStriped />| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
<Table columns={columns} data={data} hasHover idKey="id" />Hover With Sections
Section titled “Hover With Sections”| Plan | Status |
|---|---|
| Starter | Ready |
| Growth | Ready |
| Enterprise | Draft |
| 3 plans | |
<Table hasHover isStriped> <TableHeader> <TableRow> <TableHeaderCell>Plan</TableHeaderCell> <TableHeaderCell>Status</TableHeaderCell> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Starter</TableCell> <TableCell>Ready</TableCell> </TableRow> <TableRow> <TableCell>Growth</TableCell> <TableCell>Ready</TableCell> </TableRow> <TableRow> <TableCell>Enterprise</TableCell> <TableCell>Draft</TableCell> </TableRow> </TableBody> <TableFooter> <TableRow> <TableCell colSpan={2}>3 plans</TableCell> </TableRow> </TableFooter></Table>Text Overflow
Section titled “Text Overflow”| Task | Notes | Owner |
|---|---|---|
| Design review | UnbrokenIdentifier_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ with surrounding copy to compare truncation and wrapping. | Ada Lovelace |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper |
| QA pass | Run the cross-browser verification pass and log issues against the release checklist. | Katherine Johnson |
| Task | Notes | Owner |
|---|---|---|
| Design review | UnbrokenIdentifier_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ with surrounding copy to compare truncation and wrapping. | Ada Lovelace |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper |
| QA pass | Run the cross-browser verification pass and log issues against the release checklist. | Katherine Johnson |
function TextOverflowStory() { const overflowData = data.slice(0, 3).map((item, index) => index === 0 ? { ...item, notes: 'UnbrokenIdentifier_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ with surrounding copy to compare truncation and wrapping.', } : item, );
return ( <div style={{display: 'grid', gap: 24}}> <Table columns={longTextColumns} data={overflowData} textOverflow="truncate" /> <Table columns={longTextColumns} data={overflowData} textOverflow="wrap" /> </div> );}
<TextOverflowStory />Vertical Align
Section titled “Vertical Align”| Task | Notes | Owner |
|---|---|---|
| Design review | Prepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items. | Ada Lovelace |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper |
| Task | Notes | Owner |
|---|---|---|
| Design review | Prepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items. | Ada Lovelace |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper |
| Task | Notes | Owner |
|---|---|---|
| Design review | Prepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items. | Ada Lovelace |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper |
function VerticalAlignStory() { return ( <div style={{display: 'grid', gap: 24}}> <Table columns={longTextColumns} data={data.slice(0, 2)} verticalAlign="top" /> <Table columns={longTextColumns} data={data.slice(0, 2)} verticalAlign="middle" /> <Table columns={longTextColumns} data={data.slice(0, 2)} verticalAlign="bottom" /> </div> );}
<VerticalAlignStory />Column Widths
Section titled “Column Widths”| Fixed 160px | 2fr min 180px | 1fr min 120px | Fixed 96px |
|---|---|---|---|
| Design review | Prepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items. | Ada Lovelace | Jun 12 |
| Billing migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper | Jun 17 |
| QA pass | Run the cross-browser verification pass and log issues against the release checklist. | Katherine Johnson | Jun 21 |
| Docs refresh | Refresh the administrator guide and add examples for importing historical project data. | Hedy Lamarr | Jun 24 |
| Alert tuning | Tune noisy alert thresholds and group notifications by service owner for faster triage. | Alan Turing | Jun 27 |
| Research synthesis | Interview workflow owners and summarize the strongest opportunities for dashboard consolidation. | Mary Jackson | Jul 2 |
<Table columns={widthColumns} data={data} idKey="id" />Custom Cell Rendering
Section titled “Custom Cell Rendering”| Task | Owner | Priority | Status |
|---|---|---|---|
| Design review | Ada Lovelace | High | In progress |
| Billing migration | Grace Hopper | Medium | Ready |
| QA pass | Katherine Johnson | High | Blocked |
| Docs refresh | Hedy Lamarr | Low | Done |
| Alert tuning | Alan Turing | Medium | In progress |
| Research synthesis | Mary Jackson | Low | Ready |
<Table columns={[ columns[0], columns[1], { header: 'Priority', key: 'priority', renderCell: item => ( <Badge color={ item.priority === 'High' ? 'error' : item.priority === 'Medium' ? 'warning' : 'neutral' } label={item.priority} size="lg" /> ), }, columns[2], ]} data={data} idKey="id"/>Auto Columns
Section titled “Auto Columns”| Budget | Due | Id | Notes | Owner | Priority | Progress | Status | Task |
|---|---|---|---|---|---|---|---|---|
| 18200 | Jun 12 | design | Prepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items. | Ada Lovelace | High | 70% | In progress | Design review |
| 9600 | Jun 17 | migration | Move remaining accounts to the new billing pipeline after validating invoice previews with support. | Grace Hopper | Medium | 45% | Ready | Billing migration |
| 13400 | Jun 21 | qa | Run the cross-browser verification pass and log issues against the release checklist. | Katherine Johnson | High | 20% | Blocked | QA pass |
| 7200 | Jun 24 | docs | Refresh the administrator guide and add examples for importing historical project data. | Hedy Lamarr | Low | 100% | Done | Docs refresh |
<Table data={data.slice(0, 4)} idKey="id" />Children Mode
Section titled “Children Mode”| Plan | Status | Owner |
|---|---|---|
| Manual rows | Ready | Ada Lovelace |
| Rendered with table primitives. | ||
<Table> <TableHeader> <TableRow> <TableHeaderCell>Plan</TableHeaderCell> <TableHeaderCell>Status</TableHeaderCell> <TableHeaderCell>Owner</TableHeaderCell> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Manual rows</TableCell> <TableCell>Ready</TableCell> <TableCell>Ada Lovelace</TableCell> </TableRow> </TableBody> <TableFooter> <TableRow> <TableCell colSpan={3}>Rendered with table primitives.</TableCell> </TableRow> </TableFooter></Table>Children mode / Minimum width
Section titled “Children mode / Minimum width”| Workstream | Owner | Status | Next step |
|---|---|---|---|
| Documentation | Alex Morgan | Ready for review | Publish the migration guide and confirm that every example uses the stable API. |
| Accessibility | Sam Rivera | Follow-up needed | Recheck keyboard navigation at compact viewport sizes before the release candidate is tagged. |
<div style={{maxWidth: '100%', width: '560px'}}> <Table label="Release readiness" style={{minWidth: '760px'}} verticalAlign="top"> <TableHeader> <TableRow> <TableHeaderCell style={{width: '150px'}}> Workstream </TableHeaderCell> <TableHeaderCell style={{width: '130px'}}>Owner</TableHeaderCell> <TableHeaderCell style={{width: '170px'}}>Status</TableHeaderCell> <TableHeaderCell style={{width: '310px'}}> Next step </TableHeaderCell> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Documentation</TableCell> <TableCell>Alex Morgan</TableCell> <TableCell> <Badge color="success" label="Ready for review" size="lg" /> </TableCell> <TableCell> Publish the migration guide and confirm that every example uses the stable API. </TableCell> </TableRow> <TableRow> <TableCell>Accessibility</TableCell> <TableCell>Sam Rivera</TableCell> <TableCell> <Badge color="warning" label="Follow-up needed" size="lg" /> </TableCell> <TableCell> Recheck keyboard navigation at compact viewport sizes before the release candidate is tagged. </TableCell> </TableRow> </TableBody> </Table></div>Sortable
Section titled “Sortable”| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function SortableStory() { const sortable = useTableSortableState<TaskRow, string>({ data, isMultiSortEnabled: true, }); const sortPlugin = useTableSortable<TaskRow>(sortable.sortConfig); return ( <Table columns={columns} data={sortable.sortedData} idKey="id" plugins={{sortPlugin}} /> );}
<SortableStory />Selection
Section titled “Selection”| Task | Owner | Status | Budget | Due | |
|---|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 | |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 | |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 | |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 | |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 | |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function SelectionStory() { const [selectedKeys, setSelectedKeys] = useState( () => new Set<string>(['design']), ); const selection = useTableSelectionState({ data, getIsItemEnabled: item => item.status !== 'Blocked', getIsItemSelectable: item => item.status !== 'Done', idKey: 'id', selectedKeys, setSelectedKeys, }); const selectionPlugin = useTableSelection(selection.selectionConfig); return ( <Table columns={columns} data={data} idKey="id" plugins={{selectionPlugin}} /> );}
<SelectionStory />Selection / Minimum width
Section titled “Selection / Minimum width”| Task | Owner | Status | Budget | Due | |
|---|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 | |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 | |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 | |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 | |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 | |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function SelectionMinimumWidthStory() { const [selectedKeys, setSelectedKeys] = useState(() => new Set<string>()); const selection = useTableSelectionState({ data, idKey: 'id', selectedKeys, setSelectedKeys, }); const selectionPlugin = useTableSelection(selection.selectionConfig); return ( <div style={{maxWidth: '100%', width: '560px'}}> <Table columns={[ {header: 'Task', key: 'task'}, {header: 'Owner', key: 'owner'}, {header: 'Status', key: 'status'}, {align: 'end', header: 'Budget', key: 'budget'}, {header: 'Due', key: 'due'}, ]} data={data} idKey="id" plugins={{selectionPlugin}} style={{minWidth: '760px'}} /> </div> );}
<SelectionMinimumWidthStory />Row Expansion
Section titled “Row Expansion”| Name | Kind | Size | Modified | |
|---|---|---|---|---|
| src | folder | — | Jun 20 | |
components | folder | — | Jun 20 | |
utils | folder | — | Jun 17 | |
index.ts | file | 0.4 KB | Jun 20 | |
| public | folder | — | Jun 1 | |
| package.json | file | 1.8 KB | Jun 22 | |
| README.md | file | 0.6 KB | Jun 1 |
function RowExpansionStory() { const expansion = useTableRowExpansionState<FileRow>({ data: fileTree, defaultExpandedKeys: ['src'], getChildren: item => item.children, getRowKey: item => item.id, }); const expansionPlugin = useTableRowExpansion<FileRow>({ ...expansion.expansionConfig, hasExpandAllToggle: true, }); return ( <Table columns={fileColumns} data={expansion.data} hasHover idKey="id" plugins={{expansion: expansionPlugin}} /> );}
<RowExpansionStory />Row Expansion / Row click
Section titled “Row Expansion / Row click”| Name | Kind | Size | Modified | |
|---|---|---|---|---|
| src | folder | — | Jun 20 | |
| public | folder | — | Jun 1 | |
| package.json | file | 1.8 KB | Jun 22 | |
| README.md | file | 0.6 KB | Jun 1 |
function RowExpansionRowClickStory() { const expansion = useTableRowExpansionState<FileRow>({ data: fileTree, getChildren: item => item.children, getRowKey: item => item.id, }); const expansionPlugin = useTableRowExpansion<FileRow>({ ...expansion.expansionConfig, getExpanderLabel: (item, isExpanded) => isExpanded ? `Collapse ${item.name}` : `Expand ${item.name}`, hasRowClickExpansion: true, }); return ( <Table columns={fileColumns} data={expansion.data} hasHover idKey="id" plugins={{expansion: expansionPlugin}} /> );}
<RowExpansionRowClickStory />Pagination
Section titled “Pagination”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
function PaginationStory() { const [page, setPage] = useState(1); const pageSize = 2; const paginationPlugin = useTablePagination<TaskRow>({ onPageChange: setPage, page, pageSize, position: 'both', totalItems: data.length, variant: 'pages', }); return ( <Table columns={columns} data={paginateData(data, {page, pageSize})} idKey="id" plugins={{paginationPlugin}} /> );}
<PaginationStory />Column Settings
Section titled “Column Settings”| Task | Owner | Status | Due |
|---|---|---|---|
| Design review | Ada Lovelace | In progress | Jun 12 |
| Billing migration | Grace Hopper | Ready | Jun 17 |
| QA pass | Katherine Johnson | Blocked | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | Jun 24 |
| Alert tuning | Alan Turing | In progress | Jun 27 |
| Research synthesis | Mary Jackson | Ready | Jul 2 |
function ColumnSettingsStory() { const defaultKeys = ['task', 'owner', 'status', 'due']; const [activeColumnKeys, setActiveColumnKeys] = useState(defaultKeys); const settingsPlugin = useTableColumnSettings<TaskRow>({ activeColumnKeys, columns: [ {isAlwaysVisible: true, key: 'task', label: 'Task'}, {key: 'owner', label: 'Owner'}, {key: 'status', label: 'Status'}, {key: 'budget', label: 'Budget'}, {key: 'due', label: 'Due'}, ], defaultColumnKeys: defaultKeys, onChangeActiveColumnKeys: keys => { setActiveColumnKeys([...keys]); }, }); return ( <div style={{display: 'grid', gap: 12}}> <div style={{display: 'flex', gap: 8}}> <Button icon={Settings2} label="Show budget" onClick={() => { setActiveColumnKeys(['task', 'owner', 'status', 'budget', 'due']); }} size="sm" variant="secondary" /> <Button icon={Settings2} label="Reorder" onClick={() => { setActiveColumnKeys(['status', 'task', 'owner', 'due']); }} size="sm" variant="secondary" /> <Button icon={RotateCcw} label="Reset" onClick={() => { setActiveColumnKeys(defaultKeys); }} size="sm" variant="ghost" /> </div> <Table columns={columns} data={data} idKey="id" plugins={{settingsPlugin}} /> </div> );}
<ColumnSettingsStory />Column Resize
Section titled “Column Resize”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function ColumnResizeStory() { const [columnWidths, setColumnWidths] = useState<Record<string, number>>({ due: 128, task: 220, owner: 180, }); const resizePlugin = useTableColumnResize<TaskRow>({ columnWidths, columns: columns as TableColumn<Record<string, unknown>>[], minWidth: 96, onColumnResizeEnd: updates => { setColumnWidths(previous => ({...previous, ...updates})); }, }); return ( <Table columns={columns} data={data} idKey="id" plugins={{resizePlugin}} /> );}
<ColumnResizeStory />Filtering
Section titled “Filtering”Task Filter Task | Owner Filter Owner | Status Filter Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function FilteringStory() { return <FilteredTable variant="popover" />;}
function FilteredTable({variant}: {variant: TableFilterVariant}) { const {filters, onFilterChange} = useTableFilterState(); const filteredRows = useMemo(() => filterData(data, filters), [filters]); const filteringPlugin = useTableFiltering<TaskRow>({ filters, onFilterChange, searchConfig: filterSearchConfig, variant, }); return ( <Table columns={filterColumns} data={filteredRows} emptyState={<EmptyState isCompact title="No matching tasks" />} idKey="id" plugins={{filteringPlugin}} /> );}
<FilteringStory />Inline Filtering
Section titled “Inline Filtering”| Task | Owner | Status | Budget | Due |
|---|---|---|---|---|
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 |
| Billing migration | Grace Hopper | Ready | 9600 | Jun 17 |
| QA pass | Katherine Johnson | Blocked | 13400 | Jun 21 |
| Docs refresh | Hedy Lamarr | Done | 7200 | Jun 24 |
| Alert tuning | Alan Turing | In progress | 15100 | Jun 27 |
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 |
function InlineFilteringStory() { return <FilteredTable variant="inline" />;}
function FilteredTable({variant}: {variant: TableFilterVariant}) { const {filters, onFilterChange} = useTableFilterState(); const filteredRows = useMemo(() => filterData(data, filters), [filters]); const filteringPlugin = useTableFiltering<TaskRow>({ filters, onFilterChange, searchConfig: filterSearchConfig, variant, }); return ( <Table columns={filterColumns} data={filteredRows} emptyState={<EmptyState isCompact title="No matching tasks" />} idKey="id" plugins={{filteringPlugin}} /> );}
<InlineFilteringStory />Combined Plugins
Section titled “Combined Plugins”Filter Task | Filter Owner | Filter Status | ||||
|---|---|---|---|---|---|---|
| Research synthesis | Mary Jackson | Ready | 5400 | Jul 2 | ||
| Design review | Ada Lovelace | In progress | 18200 | Jun 12 | ||
Annotate screens | Ada Lovelace | In progress | 4200 | Jun 10 |
function CombinedPluginsStory() { const [page, setPage] = useState(1); const [selectedKeys, setSelectedKeys] = useState(() => new Set<string>()); const {filters, onFilterChange} = useTableFilterState(); // Composition order: filter and sort operate on the root rows of the tree, // expansion flattens the visible rows, and pagination slices the flattened // output last (paginating before flattening would orphan child rows). const filteredRows = useMemo( () => filterData(combinedTaskTree, filters), [filters], ); const sortable = useTableSortableState<TaskRow, string>({ data: filteredRows, defaultSort: [{direction: 'ascending', sortKey: 'due'}], }); const expansion = useTableRowExpansionState<TaskRow>({ data: sortable.sortedData, defaultExpandedKeys: ['design'], getChildren: item => item.subtasks, getRowKey: item => item.id, }); const selection = useTableSelectionState({ data: expansion.data, idKey: 'id', selectedKeys, setSelectedKeys, }); const pageSize = 3; const sortPlugin = useTableSortable<TaskRow>(sortable.sortConfig); const expansionPlugin = useTableRowExpansion(expansion.expansionConfig); const selectionPlugin = useTableSelection(selection.selectionConfig); const filteringPlugin = useTableFiltering<TaskRow>({ filters, onFilterChange, searchConfig: filterSearchConfig, variant: 'popover', }); const paginationPlugin = useTablePagination<TaskRow>({ onPageChange: setPage, page, pageSize, totalItems: expansion.data.length, variant: 'compact', }); return ( <Table columns={filterColumns} data={paginateData(expansion.data, {page, pageSize})} idKey="id" plugins={{ expansionPlugin, selectionPlugin, sortPlugin, filteringPlugin, paginationPlugin, }} /> );}
<CombinedPluginsStory />| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Table primitives rendered instead of data-driven content. When provided, columns/data are ignored and the children are rendered as-is. |
className | string | — | Additional CSS class names applied to the table element. |
columns | TableColumn<T>[] | — | Column definitions. When omitted, columns are inferred from data. |
data | T[] | — | Row data rendered into the table body. |
data-testid | string | — | Test ID applied to the table element. |
density | "compact" | "balanced" | "spacious" | 'balanced' | Spacing density for rows and cells. |
dividers | "none" | "grid" | "columns" | "rows" | 'rows' | Which divider lines to show between cells. |
emptyState | ReactNode | — | Content shown when data is an empty array. Omit for the default empty state; pass null to render nothing. |
hasHover | boolean | false | Whether rows highlight on hover. |
idKey | (keyof T & string) | ((item: T) => number | string) | — | Stable row identity, used as the React key for each body row. |
isStriped | boolean | false | Whether alternating rows have a subtle background. |
label | string | 'Table' | Name of the table, used to label its horizontal scroll region. |
plugins | Record<string, TablePlugin<T>> | TablePlugin<T>[] | — | Plugin map or array that extends table behavior. |
ref | Ref<HTMLTableElement> | — | Ref forwarded to the table element. |
style | CSSProperties | — | Inline styles applied to the table element. |
tableProps | HTMLAttributes<HTMLTableElement> | — | Extra HTML attributes spread onto the table element. |
textOverflow | "wrap" | "truncate" | 'wrap' | How overflowing cell text is handled. |
verticalAlign | "bottom" | "top" | "middle" | 'middle' | Vertical alignment of cell content. |
TableBody
Section titled “TableBody”Wraps table body rows in a `<tbody>` element.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Table row elements rendered inside the body. |
className | string | — | Additional CSS class names applied to the tbody. |
data-testid | string | — | Test ID applied to the tbody. |
ref | Ref<HTMLTableSectionElement> | — | Ref forwarded to the tbody element. |
style | CSSProperties | — | Inline styles applied to the tbody. |
TableCell
Section titled “TableCell”Table data cell with density, alignment, and divider styling from context.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Cell content. |
className | string | — | Additional CSS class names applied to the td. |
colSpan | number | — | Number of columns the cell spans. |
data-testid | string | — | Test ID applied to the td. |
headers | string | — | Space-separated list of header cell IDs this cell relates to. |
ref | Ref<HTMLTableCellElement> | — | Ref forwarded to the td element. |
rowSpan | number | — | Number of rows the cell spans. |
style | CSSProperties | — | Inline styles applied to the td. |
TableFooter
Section titled “TableFooter”Wraps table footer rows in a `<tfoot>` element. Rows rendered inside opt out of the table's hover and striping styling.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Footer row elements rendered inside the tfoot. |
className | string | — | Additional CSS class names applied to the tfoot. |
data-testid | string | — | Test ID applied to the tfoot. |
ref | Ref<HTMLTableSectionElement> | — | Ref forwarded to the tfoot element. |
style | CSSProperties | — | Inline styles applied to the tfoot. |
TableHeader
Section titled “TableHeader”Wraps table header rows in a `<thead>` element. Rows rendered inside opt out of the table's hover and striping styling.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Header row elements rendered inside the thead. |
className | string | — | Additional CSS class names applied to the thead. |
data-testid | string | — | Test ID applied to the thead. |
ref | Ref<HTMLTableSectionElement> | — | Ref forwarded to the thead element. |
style | CSSProperties | — | Inline styles applied to the thead. |
TableHeaderCell
Section titled “TableHeaderCell”Table header cell with density and divider styling from context.
| Prop | Type | Default | Description |
|---|---|---|---|
aria-sort | AriaAttributes['aria-sort'] | — | Indicates whether and how the column is sorted. |
children | ReactNode | — | Header cell content. |
className | string | — | Additional CSS class names applied to the th. |
data-column-key | string | — | Column key used by table plugins. |
data-testid | string | — | Test ID applied to the th. |
ref | Ref<HTMLTableCellElement> | — | Ref forwarded to the th element. |
scope | ThHTMLAttributes<HTMLTableCellElement>['scope'] | 'col' | Scope of the header cell. |
style | CSSProperties | — | Inline styles applied to the th. |
title | string | — | Native tooltip text applied to the th. |
TableRow
Section titled “TableRow”Table row with hover and striped styling from context. Header and footer rows are not interactive, so they render without that styling even when the surrounding table enables it.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Cell elements rendered inside the row. |
className | string | — | Additional CSS class names applied to the tr. |
data-testid | string | — | Test ID applied to the tr. |
ref | Ref<HTMLTableRowElement> | — | Ref forwarded to the tr element. |
style | CSSProperties | — | Inline styles applied to the tr. |