Skip to content

Table

Data table with sorting, filtering, and column resize plugins.

TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 2
<Table columns={columns} data={data} idKey="id" />
TaskOwnerStatusBudgetDue

No tasks found

Try 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"
/>
}
/>
TaskOwnerStatusBudgetDue

No data

<Table columns={columns} data={[]} />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 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 />
SourceCost
Compute$18.00
Storage$6.00
Total$24.00
SourceCost
Compute$18.00
Storage$6.00
Total$24.00
SourceCost
Compute$18.00
Storage$6.00
Total$24.00
SourceCost
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 />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 2
<Table columns={columns} data={data} idKey="id" isStriped />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 2
<Table columns={columns} data={data} hasHover idKey="id" />
PlanStatus
StarterReady
GrowthReady
EnterpriseDraft
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>
TaskNotesOwner
Design reviewUnbrokenIdentifier_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ with surrounding copy to compare truncation and wrapping.Ada Lovelace
Billing migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace Hopper
QA passRun the cross-browser verification pass and log issues against the release checklist.Katherine Johnson
TaskNotesOwner
Design reviewUnbrokenIdentifier_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ with surrounding copy to compare truncation and wrapping.Ada Lovelace
Billing migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace Hopper
QA passRun 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 />
TaskNotesOwner
Design reviewPrepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items.Ada Lovelace
Billing migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace Hopper
TaskNotesOwner
Design reviewPrepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items.Ada Lovelace
Billing migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace Hopper
TaskNotesOwner
Design reviewPrepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items.Ada Lovelace
Billing migrationMove 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 />
Fixed 160px2fr min 180px1fr min 120pxFixed 96px
Design reviewPrepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items.Ada LovelaceJun 12
Billing migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace HopperJun 17
QA passRun the cross-browser verification pass and log issues against the release checklist.Katherine JohnsonJun 21
Docs refreshRefresh the administrator guide and add examples for importing historical project data.Hedy LamarrJun 24
Alert tuningTune noisy alert thresholds and group notifications by service owner for faster triage.Alan TuringJun 27
Research synthesisInterview workflow owners and summarize the strongest opportunities for dashboard consolidation.Mary JacksonJul 2
<Table columns={widthColumns} data={data} idKey="id" />
TaskOwnerPriorityStatus
Design reviewAda LovelaceHighIn progress
Billing migrationGrace HopperMediumReady
QA passKatherine JohnsonHighBlocked
Docs refreshHedy LamarrLowDone
Alert tuningAlan TuringMediumIn progress
Research synthesisMary JacksonLowReady
<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"
/>
BudgetDueIdNotesOwnerPriorityProgressStatusTask
18200Jun 12designPrepare the final handoff package with annotated screenshots, links to key decisions, and open follow-up items.Ada LovelaceHigh70%In progressDesign review
9600Jun 17migrationMove remaining accounts to the new billing pipeline after validating invoice previews with support.Grace HopperMedium45%ReadyBilling migration
13400Jun 21qaRun the cross-browser verification pass and log issues against the release checklist.Katherine JohnsonHigh20%BlockedQA pass
7200Jun 24docsRefresh the administrator guide and add examples for importing historical project data.Hedy LamarrLow100%DoneDocs refresh
<Table data={data.slice(0, 4)} idKey="id" />
PlanStatusOwner
Manual rowsReadyAda 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>
WorkstreamOwnerStatusNext step
DocumentationAlex MorganReady for reviewPublish the migration guide and confirm that every example uses the stable API.
AccessibilitySam RiveraFollow-up neededRecheck 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>
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
NameKindSizeModified
srcfolderJun 20
components
folderJun 20
utils
folderJun 17
index.ts
file0.4 KBJun 20
publicfolderJun 1
package.jsonfile1.8 KBJun 22
README.mdfile0.6 KBJun 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 />
NameKindSizeModified
srcfolderJun 20
publicfolderJun 1
package.jsonfile1.8 KBJun 22
README.mdfile0.6 KBJun 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 />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 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 />
TaskOwnerStatusDue
Design reviewAda LovelaceIn progressJun 12
Billing migrationGrace HopperReadyJun 17
QA passKatherine JohnsonBlockedJun 21
Docs refreshHedy LamarrDoneJun 24
Alert tuningAlan TuringIn progressJun 27
Research synthesisMary JacksonReadyJul 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 />
TaskOwnerStatusBudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
Task
Owner
Status
BudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
Task
Owner
Status
BudgetDue
Design reviewAda LovelaceIn progress18200Jun 12
Billing migrationGrace HopperReady9600Jun 17
QA passKatherine JohnsonBlocked13400Jun 21
Docs refreshHedy LamarrDone7200Jun 24
Alert tuningAlan TuringIn progress15100Jun 27
Research synthesisMary JacksonReady5400Jul 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 />
Research synthesisMary JacksonReady5400Jul 2
Design reviewAda LovelaceIn progress18200Jun 12
Annotate screens
Ada LovelaceIn progress4200Jun 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 />
PropTypeDefaultDescription
childrenReactNodeTable primitives rendered instead of data-driven content. When provided, columns/data are ignored and the children are rendered as-is.
classNamestringAdditional CSS class names applied to the table element.
columnsTableColumn<T>[]Column definitions. When omitted, columns are inferred from data.
dataT[]Row data rendered into the table body.
data-testidstringTest 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.
emptyStateReactNodeContent shown when data is an empty array. Omit for the default empty state; pass null to render nothing.
hasHoverbooleanfalseWhether rows highlight on hover.
idKey(keyof T & string) | ((item: T) => number | string)Stable row identity, used as the React key for each body row.
isStripedbooleanfalseWhether alternating rows have a subtle background.
labelstring'Table'Name of the table, used to label its horizontal scroll region.
pluginsRecord<string, TablePlugin<T>> | TablePlugin<T>[]Plugin map or array that extends table behavior.
refRef<HTMLTableElement>Ref forwarded to the table element.
styleCSSPropertiesInline styles applied to the table element.
tablePropsHTMLAttributes<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.

Wraps table body rows in a `<tbody>` element.

PropTypeDefaultDescription
children*ReactNodeTable row elements rendered inside the body.
classNamestringAdditional CSS class names applied to the tbody.
data-testidstringTest ID applied to the tbody.
refRef<HTMLTableSectionElement>Ref forwarded to the tbody element.
styleCSSPropertiesInline styles applied to the tbody.

Table data cell with density, alignment, and divider styling from context.

PropTypeDefaultDescription
childrenReactNodeCell content.
classNamestringAdditional CSS class names applied to the td.
colSpannumberNumber of columns the cell spans.
data-testidstringTest ID applied to the td.
headersstringSpace-separated list of header cell IDs this cell relates to.
refRef<HTMLTableCellElement>Ref forwarded to the td element.
rowSpannumberNumber of rows the cell spans.
styleCSSPropertiesInline styles applied to the td.

Wraps table footer rows in a `<tfoot>` element. Rows rendered inside opt out of the table's hover and striping styling.

PropTypeDefaultDescription
children*ReactNodeFooter row elements rendered inside the tfoot.
classNamestringAdditional CSS class names applied to the tfoot.
data-testidstringTest ID applied to the tfoot.
refRef<HTMLTableSectionElement>Ref forwarded to the tfoot element.
styleCSSPropertiesInline styles applied to the tfoot.

Wraps table header rows in a `<thead>` element. Rows rendered inside opt out of the table's hover and striping styling.

PropTypeDefaultDescription
children*ReactNodeHeader row elements rendered inside the thead.
classNamestringAdditional CSS class names applied to the thead.
data-testidstringTest ID applied to the thead.
refRef<HTMLTableSectionElement>Ref forwarded to the thead element.
styleCSSPropertiesInline styles applied to the thead.

Table header cell with density and divider styling from context.

PropTypeDefaultDescription
aria-sortAriaAttributes['aria-sort']Indicates whether and how the column is sorted.
childrenReactNodeHeader cell content.
classNamestringAdditional CSS class names applied to the th.
data-column-keystringColumn key used by table plugins.
data-testidstringTest ID applied to the th.
refRef<HTMLTableCellElement>Ref forwarded to the th element.
scopeThHTMLAttributes<HTMLTableCellElement>['scope']'col'Scope of the header cell.
styleCSSPropertiesInline styles applied to the th.
titlestringNative tooltip text applied to the th.

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.

PropTypeDefaultDescription
children*ReactNodeCell elements rendered inside the row.
classNamestringAdditional CSS class names applied to the tr.
data-testidstringTest ID applied to the tr.
refRef<HTMLTableRowElement>Ref forwarded to the tr element.
styleCSSPropertiesInline styles applied to the tr.