Skip to content

Table

import { Table } from '@yarcl/react';
Invoices
InvoiceCustomerStatus
INV-1042Ada LovelacePaid$1,200.00
INV-1043Grace HopperPending$860.50
INV-1044Alan TuringOverdue$45.00
INV-1045Katherine JohnsonPaid$13,075.25
<Table density="compact" radius="md" striped interactive stickyHeader caption="Invoices">
<Table.Head>
<Table.Row>
<Table.SelectAllCell checked={allSelected} indeterminate={someSelected} onCheckedChange={toggleAll} />
<Table.HeaderCell sortable sortDirection={sortDir} onSort={setSortDir}>Customer</Table.HeaderCell>
<Table.HeaderCell align="end">Amount</Table.HeaderCell>
</Table.Row>
</Table.Head>
<Table.VirtualBody items={invoices} estimateRowHeight={48} getItemKey={(invoice) => invoice.id}>
{(invoice) => (
<Table.Row key={invoice.id} selected={selectedIds.has(invoice.id)}>
<Table.SelectionCell
aria-label={`Select ${invoice.customer}`}
checked={selectedIds.has(invoice.id)}
onCheckedChange={() => toggleRow(invoice.id)}
/>
<Table.Cell>{invoice.customer}</Table.Cell>
<Table.Cell align="end">${invoice.amount.toFixed(2)}</Table.Cell>
</Table.Row>
)}
</Table.VirtualBody>
</Table>
  • density accepts the keys of your density group.
  • Text without an explicit text style follows the cell’s density font size, so muted and truncate can be used alongside plain cell text. Use textStyle to opt into a specific text style.
  • radius accepts the keys of your radii group and styles the table frame.
  • sortable on Table.HeaderCell manages aria-sort state and accessible sort triggers.
  • Table.SelectAllCell and Table.SelectionCell provide accessible row selection checkboxes.
  • Table.VirtualBody renders a window of rows around the viewport. Choose measured heights for wrapped content or an explicit fixed height when every row is equal.
  • align="end" also uses tabular numbers, so amounts line up.
  • caption is visible and names the table for screen readers.

Use measured mode when descriptions wrap, rows expand, or density changes their height:

<Table stickyHeader caption="Orders" wrapStyle={{ maxHeight: '24rem' }}>
<Table.Head>
<Table.Row>
<Table.HeaderCell>Customer</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
</Table.Row>
</Table.Head>
<Table.VirtualBody
items={orders}
estimateRowHeight={48}
getItemKey={(order) => order.id}
overscan={5}
>
{(order) => (
<Table.Row>
<Table.Cell>{order.customer}</Table.Cell>
<Table.Cell>{order.description}</Table.Cell>
</Table.Row>
)}
</Table.VirtualBody>
</Table>

estimateRowHeight is a positive initial estimate in CSS pixels. ResizeObserver replaces it with each rendered row’s actual height. Unvisited rows retain their estimate, so the scrollbar becomes more accurate as you scroll. Choose an estimate close to a typical row to reduce adjustments.

getItemKey is required in measured mode. Return a unique, stable ID that follows the item through sorting and filtering. An array index is unsuitable for mutable order. Measurements are cached by this key, refreshed when visible content resizes, and invalidated when table width, density or theme changes. The first visible item remains the scroll anchor when earlier rows are remeasured. The focused row and its immediate neighbors stay mounted so Tab and Shift+Tab can continue across virtual windows. The sticky table wrapper can receive keyboard focus; use PageDown to scroll, Home for the first row and End for the last row.

Render exactly one Table.Row or native tr per item. A custom row component must spread its props onto its tr. Row and body refs remain available. Keep column widths stable, for example with tableLayout: 'fixed' or a colgroup, so different windows do not continually change text wrapping.

For fixed mode, pass rowHeight instead of estimateRowHeight. Rows must all render at that height, including their padding and borders. Both modes reject duplicate item keys. Update it if density or content changes the height:

<Table.VirtualBody items={orders} rowHeight={36} getItemKey={(order) => order.id}>
{(order) => (
<Table.Row>
<Table.Cell>{order.customer}</Table.Cell>
<Table.Cell>{order.total}</Table.Cell>
</Table.Row>
)}
</Table.VirtualBody>

overscan is a nonnegative integer. Both modes use the table wrapper as their scroll container. Pass scrollRef when an ancestor handles scrolling; captions and content before the table are accounted for in the offsets. Use Table.Body when every row must be present for printing, browser find or assistive technology traversal.

Configure root, header, row and cell through component parts. The root is the scrollable frame; header cells expose data-part="header", body cells expose "cell", and compound rows expose "row". Use wrapClassName to scope application CSS to a table frame.

Add typed column widths, pointer and keyboard resize handles, and visibility checkboxes with useTableColumns, Table.Columns and Table.ColumnVisibility. They work with sorting, selection, sticky headers and both virtualization modes. See the complete table columns guide.

PropTypeDefaultDescription
captionReactNodeVisible caption describing the table. Also its accessible name.
densityDensityconfigconfig.defaults.densityCell padding and font size, from the density config.
interactivebooleanHighlights the row under the pointer. Use when rows are clickable.
radiusRadiusconfigconfig.components.Table.radius ?? config.defaults.radiusCorner radius of the table frame, from the radii config.
stickyHeaderbooleanEnables a scrollable container with sticky header support.
stripedbooleanShades every other row.
wrapClassNamestringAdditional class name for the outer table wrapper.
wrapStyleCSSPropertiesAdditional inline styles for the outer table wrapper.
PropTypeDefaultDescription
alignCellAlign'start'Content alignment.
onSort(direction: 'ascending' | 'descending') => voidCallback invoked when the user activates the sort button.
resizeTableColumnResizerPropsOptional column-width separator beside the header content or sort button.
sortablebooleanIndicates whether the column is sortable.
sortDirectionfalse | SortDirection | nullCurrent sort direction of the column.
sortLabelstringAccessible label for the sort action.
PropTypeDefaultDescription
alignCellAlign'start'Content alignment.
PropTypeDefaultDescription
selectedbooleanIndicates whether the row is currently selected.
PropTypeDefaultDescription
aria-labelstringconfig.labels.selectAllRowsAccessible label for screen readers.
checkedbooleanChecked state when all rows are selected.
disabledbooleanDisables the select all checkbox.
indeterminatebooleanIndeterminate state when a subset of rows is selected.
onCheckedChange(checked: boolean) => voidChange handler when the checkbox is toggled.
PropTypeDefaultDescription
aria-label requiredstringAccessible label for the row checkbox.
checkedbooleanChecked state of the row selection checkbox.
disabledbooleanDisables the row selection checkbox.
onCheckedChange(checked: boolean) => voidChange handler when the row checkbox is toggled.
PropTypeDefaultDescription
children required(item: T, index: number) => ReactElement<DetailedHTMLProps<HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>>Render exactly one Table.Row or tr per item. Custom row components must spread their props onto a tr.
estimateRowHeight requirednumberInitial estimate in CSS pixels. Actual row heights are measured with ResizeObserver.
getItemKey required(item: T, index: number) => string | numberStable, unique key for each item, independent of its position after sorting or filtering.
items requiredT[]Array of items to render.
overscannumber5Number of buffer rows above and below the viewport. Must be a nonnegative integer.
scrollRefRefObject<HTMLElement | null>Optional custom scroll container ref instead of the table wrapper.
PropTypeDefaultDescription
children required(item: T, index: number) => ReactNodeRender prop called for each visible item.
items requiredT[]Array of items to render.
rowHeight requirednumberRendered height of every row in CSS pixels. Opts into fixed-height virtualization.
getItemKey(item: T, index: number) => string | numberKey extractor. Fixed mode defaults to item.id or index.
overscannumber5Number of buffer rows above and below the viewport. Must be a nonnegative integer.
scrollRefRefObject<HTMLElement | null>Optional custom scroll container ref instead of the table wrapper.