Table
Rows and columns of data with sorting, selection, nested rows and drag and drop. Describe the columns up front, then render a TableRow for every item.
Image
Title
Status
import {
Badge,
Table,
TableCell,
TableRow,
TableThumbnail,
TableTitle
} from 'alinea/components'
const products = [
{id: 'oak-dining-chair', title: 'Oak dining chair', status: 'published'},
{id: 'walnut-stools', title: 'Walnut stools', status: 'draft'},
{id: 'linen-lounge-chair', title: 'Linen lounge chair', status: 'archived'}
] as const
export function TableExample() {
return (
<div style={{width: 520, height: 180}}>
<Table
aria-label="Products"
items={products}
columns={[
{id: 'image', header: 'Image', width: 72},
{id: 'title', header: 'Title', width: '1fr'},
{id: 'status', header: 'Status', width: 120}
]}
>
{product => (
<TableRow id={product.id} textValue={product.title}>
<TableThumbnail src={`/catalog/${product.id}.jpg`} alt="" />
<TableTitle title={product.title} label="Products" />
<TableCell>
<Badge size="sm" status={product.status}>
{product.status}
</Badge>
</TableCell>
</TableRow>
)}
</Table>
</div>
)
}Selection and sorting
Set a selectionMode to let editors select rows, showSelectionControls adds a checkbox to every row. Mark columns as sortable and sort the items in onSortChange.
import {
type SortDescriptor,
Table,
TableCell,
TableRow,
TableTitle
} from 'alinea/components'
import {useState} from 'react'
const products = [
{id: 'shirt', title: 'Linen shirt', price: 89},
{id: 'chair', title: 'Oak dining chair', price: 245},
{id: 'stool', title: 'Walnut stool', price: 160},
{id: 'lamp', title: 'Ceramic table lamp', price: 120}
]
export function TableSelectionExample() {
const [sort, setSort] = useState<SortDescriptor>({
column: 'title',
direction: 'asc'
})
const sorted = [...products].sort((a, b) =>
sort.column === 'price' ? a.price - b.price : a.title.localeCompare(b.title)
)
if (sort.direction === 'desc') sorted.reverse()
return (
<div style={{width: 520, height: 230}}>
<Table
aria-label="Products"
items={sorted}
columns={[
{id: 'title', header: 'Title', width: '1fr', sortable: true},
{
id: 'price',
header: 'Price',
width: 120,
align: 'end',
sortable: true
}
]}
selectionMode="multiple"
showSelectionControls
defaultSelectedKeys={new Set(['chair'])}
sortDescriptor={sort}
onSortChange={setSort}
>
{product => (
<TableRow id={product.id} textValue={product.title}>
<TableTitle title={product.title} />
<TableCell align="end">€{product.price}</TableCell>
</TableRow>
)}
</Table>
</div>
)
}Props
<Table>
PropTypeDefaultDescription
items*Iterable<T>Default –
columns*ReadonlyArray<TableColumn>Default –
showHeaderbooleanDefault trueShow the column headers, defaults to true
expandablebooleanDefault falseReserve space for expand toggles so titles line up, set when rows nest
rowHeightnumberDefault 44
selectionBehavior'toggle' | 'replace'Default 'toggle'How pointer clicks select rows. With
toggle (the default) a click runs the row action, or toggles its selection while rows are selected. With replace a click selects only that row and a double click or Enter runs the row action.showSelectionControlsbooleanDefault –Show a selection checkbox per row, defaults to multiple selection
variant'surface' | 'plain'Default 'surface'
plain drops the rounded surface, eg. when the table fills a panelexpandedKeysIterable<Key>Default –
defaultExpandedKeysIterable<Key>Default –
onExpandedChange(keys: Set<Key>) => voidDefault –
sortDescriptorSortDescriptorDefault –
onSortChange(descriptor: SortDescriptor) => voidDefault –
onRowAction(key: Key) => voidDefault –Called when a row is activated (see
selectionBehavior), rows can override it with their own onActionrenderEmptyState() => ReactNodeDefault –
dependenciesReadonlyArray<unknown>Default –Rows are cached per item, list the values
children reads besides the item to render them again when those changechildren*(item: T) => ReactElementDefault –
<TableRow>
PropTypeDefaultDescription
id*KeyDefault –
textValue*stringDefault –Text used for typeahead and as the accessible row name
hasChildrenbooleanDefault –Shows the expand toggle, also before the nested rows are loaded
rowsReactNodeDefault –Nested TableRows, rendered when the row is expanded. Pass them only once expanded to load them lazily, eg. from a component that renders the rows of already loaded data.
selectablebooleanDefault trueSet to false to disable selecting the row, its action still runs
highlightedbooleanDefault –Highlights the row, eg. to mark items that are already in use
onAction() => voidDefault –Called when the row is activated, overrides
onRowActiononClick() => voidDefault –Called on every click or tap of the row, next to its selection. Use it instead of
onAction to act on a single click with the replace selection behavior, where onAction needs a double click.onDoubleClick() => voidDefault –
Also accepts data-* attributes.
<TableCell>
PropTypeDefaultDescription
labelReactNodeDefault –A small caption above the value, like the dashboard explorer shows its columns when the header is hidden
align'start' | 'end' | 'center'Default –
titlestringDefault –Tooltip text
Also accepts className and style.
<TableThumbnail>
An image cell, sized to the row height
PropTypeDefaultDescription
srcstringDefault –
altstringDefault ''
Also accepts className and style.
<TableTitle>
PropTypeDefaultDescription
iconIconTypeDefault –Doubles as the drag handle of the row when rows can be dragged
title*ReactNodeDefault –
labelReactNodeDefault –A small caption above the title, eg. the parent path
Also accepts className and style.
Accessibility
Built on the React Aria grid: the arrow keys move between rows, Space selects a row and Enter runs its action. Sortable column headers announce their sort direction.