Table
Tables display structured data in rows and columns with support for sorting, selection, column resizing, and infinite scrolling.
Completeness: behavior-required
The stylesheet is only the visible half of this component. It also needs a keyboard
map, focus managed across more than one element, ARIA attributes that point at other
nodes, and [data-*] attributes that only running code sets — so a CSS-only port will
not reproduce it. Use @blakeui/react, or read the interaction contract from the MCP
server with get_component_behavior("Table") and build the behaviour yourself.
Import
import { Table } from '@blakeui/react';Usage
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
import {Table} from "@blakeui/react";
export function Basic() {
return (
<Table>Anatomy
Import the Table component and access all parts using dot notation.
import { Table } from '@blakeui/react';
export default () => (
<Table>
<Table.ScrollContainer>
<Table.Content aria-label="Example table">
<Table.Header>
<Table.Column>Name</Table.Column>
<Table.Column>Role</Table.Column>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>Kate Moore</Table.Cell>
<Table.Cell>CEO</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Content>
</Table.ScrollContainer>
<Table.Footer>{/* Optional footer content */}</Table.Footer>
</Table>
);Secondary Variant
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
import {Table} from "@blakeui/react";
export function SecondaryVariant() {
return (
<Table variant="secondary">Sorting
Columns can be made sortable using the allowsSorting prop on Table.Column. Use sortDescriptor and onSortChange on Table.Content to manage sort state.
| Name | Role | Status | |
|---|---|---|---|
| Emily Davis | Product Manager | Inactive | emily@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Kate Moore | CEO | Active | kate@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
"use client";
import type {SortDescriptor} from "@blakeui/react";
import {Table, cn} from "@blakeui/react";Selection
Enable row selection with selectionMode on Table.Content. Use Checkbox with slot="selection" for select-all and per-row checkboxes.
| Name | Role | Status | ||
|---|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com | |
| John Smith | CTO | Active | john@acme.com | |
| Sara Johnson | CMO | On Leave | sara@acme.com | |
| Michael Brown | CFO | Active | michael@acme.com |
Selected: None
"use client";
import type {Selection} from "@blakeui/react";
import {Checkbox, Table} from "@blakeui/react";Custom Cells
| Worker ID | Member | Role | Status | Actions | |
|---|---|---|---|---|---|
#1234567 | ED Emily Davisemily@acme.com | Product Manager | Inactive | ||
#5273849 | JS John Smithjohn@acme.com | Chief Technology Officer | Active | ||
#4586932 | KM Kate Moorekate@acme.com | Chief Executive Officer | Active | ||
#8293746 | MB Michael Brownmichael@acme.com | Chief Financial Officer | Active | ||
#7492836 | SJ Sara Johnsonsara@acme.com | Chief Marketing Officer | On Leave |
"use client";
import type {Selection, SortDescriptor} from "@blakeui/react";
import {Avatar, Button, Checkbox, Chip, Table, cn} from "@blakeui/react";Expandable Rows
Rows can be nested to display hierarchical data. Use the treeColumn prop to designate a column, and render a Button with slot="chevron" in that column’s cells so users can expand and collapse the row. Use the expandedKeys prop to control which rows are expanded.
| Name | Type | Date Modified |
|---|---|---|
| Documents | Directory | 10/20/2025 |
| Project | Directory | 8/2/2025 |
| Photos | Directory | 2/3/2026 |
"use client";
import type {Selection} from "@blakeui/react";
import {Button, Table, cn} from "@blakeui/react";Pagination
Use Table.Footer to add a pagination component below the table.
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
"use client";
import {Pagination, Table} from "@blakeui/react";
import {useMemo, useState} from "react";
Column Resizing
Wrap the table in Table.ResizableContainer and add Table.ColumnResizer inside each resizable column.
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
| Emily Davis | Product Manager | Inactive | emily@acme.com |
import {Chip, Table} from "@blakeui/react";
export function ColumnResizing() {
return (
<Table>Empty State
Use renderEmptyState on Table.Body to display a custom message when the table has no data.
| Name | Role | Status | |
|---|---|---|---|
No results found | |||
"use client";
import {EmptyState, Table} from "@blakeui/react";
import {Icon} from "@iconify/react";
Async Loading
Use Table.LoadMore for infinite scrolling. It renders a sentinel row that triggers onLoadMore when scrolled into view.
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
| Emily Davis | Product Manager | Inactive | emily@acme.com |
| Davis Wilson | Lead Designer | Active | davis@acme.com |
"use client";
import {Chip, Spinner, Table} from "@blakeui/react";
import {useCallback, useRef, useState} from "react";
Virtualization
Table supports virtualization through Virtualizer, enabling efficient rendering of large datasets by displaying only the rows visible within the viewport.
"use client";
import {Table, TableLayout, Virtualizer} from "@blakeui/react";
interface User {TanStack Table
blakeUI's Table works as a rendering layer on top of headless table libraries. This example uses TanStack Table for column definitions, sorting, and pagination — while blakeUI handles styling and accessibility.
| Name | Role | Status | |
|---|---|---|---|
| Kate Moore | CEO | Active | kate@acme.com |
| John Smith | CTO | Active | john@acme.com |
| Sara Johnson | CMO | On Leave | sara@acme.com |
| Michael Brown | CFO | Active | michael@acme.com |
"use client";
import type {SortDescriptor} from "@blakeui/react";
import type {SortingState} from "@tanstack/react-table";
With Filters
Compose a filter toolbar above the table: search, a combined Status / Role filters popover, column reordering and show / hide, row selection, and pagination. This is composition in the consumer — the Table component itself is unchanged.
| Member | Worker ID | Role | Status | Actions | |
|---|---|---|---|---|---|
AJ Ava Jacksonava@acme.com | #7890123 | Data Analyst | Inactive | ||
DW Davis Wilsondavis@acme.com | #9876543 | Lead Designer | Active | ||
ED Emily Davisemily@acme.com | #1234567 | Product Manager | Inactive | ||
JT James Taylorjames@acme.com | #4567890 | Backend Engineer | Active | ||
JS John Smithjohn@acme.com | #5273849 | Chief Technology Officer | Active |
"use client";
import type {Dispatch, ReactNode, SetStateAction} from "react";
import type {Key, Selection, SortDescriptor} from "react-aria-components";
Styling
Passing Tailwind CSS classes
You can customize individual Table parts:
import { Table } from '@blakeui/react';
function CustomTable() {
return (
<Table className="border border-purple-200">
<Table.ScrollContainer>
<Table.Content aria-label="Custom styled table">
<Table.Header className="bg-purple-50">
<Table.Column>Name</Table.Column>
</Table.Header>
<Table.Body>
<Table.Row className="hover:bg-purple-50">
<Table.Cell>Kate Moore</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Content>
</Table.ScrollContainer>
</Table>
);
}Customizing the component classes
To customize the Table component classes, you can use the @layer components directive.
Learn more.
A worked example is in Styling.
blakeUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The Table component uses these CSS classes (View source styles):
Base Classes
.table-root- Root container (namedtable-rootinstead oftablebecausetableis a built-in Tailwind CSS utility class fordisplay: table).table__scroll-container- Horizontal scroll wrapper with custom scrollbar.table__content- The<table>element.table__header- Header row (<thead>).table__column- Column header cell (<th>).table__body- Body section (<tbody>).table__row- Row element (<tr>).table__cell- Data cell (<td>).table__footer- Footer container (outside table)
Advanced Classes
.table__column-resizer- Drag handle for column resizing.table__resizable-container- Wrapper enabling column resizing.table__load-more- Sentinel row for infinite scrolling.table__load-more-content- Styled container for the loading indicator
Variant Classes
.table-root--primary- Gray background container with card-style body (default).table-root--secondary- No background, standalone rounded headers
Interactive States
The Table supports both CSS pseudo-classes and data attributes for flexibility:
- Hover:
:hoveror[data-hovered="true"](row background change) - Selected:
[data-selected="true"](row highlight) - Focus:
:focus-visibleor[data-focus-visible="true"](inset focus ring on rows, columns, and cells) - Disabled:
:disabledor[aria-disabled="true"](reduced opacity) - Sortable:
[data-allows-sorting="true"](interactive cursor on columns) - Dragging:
[data-dragging="true"](reduced opacity) - Drop Target:
[data-drop-target="true"](accent background)
API Reference
Table Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "primary" | Visual variant. Primary has a gray background container; secondary is flat with transparent rows. |
className | string | - | Additional CSS classes for the root container |
children | React.ReactNode | - | Table content (ScrollContainer, Footer, etc.) |
Table.ScrollContainer Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Table.Content element |
Table.Content Props
Inherits from React Aria Table.
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | - | Accessible label for the table |
selectionMode | "none" | "single" | "multiple" | "none" | Selection behavior |
selectedKeys | Selection | - | Controlled selected keys |
onSelectionChange | (keys: Selection) => void | - | Selection change handler |
sortDescriptor | SortDescriptor | - | Current sort state |
onSortChange | (descriptor: SortDescriptor) => void | - | Sort change handler |
className | string | - | Additional CSS classes |
Table.Header Props
Inherits from React Aria TableHeader.
| Prop | Type | Default | Description |
|---|---|---|---|
columns | T[] | - | Dynamic column data for render prop pattern |
children | React.ReactNode | (column: T) => React.ReactNode | - | Static columns or render prop |
Table.Column Props
Inherits from React Aria Column.
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | - | Column identifier |
allowsSorting | boolean | false | Whether the column is sortable |
isRowHeader | boolean | false | Whether this column is a row header |
defaultWidth | string | number | - | Default width for resizable columns |
minWidth | number | - | Minimum width for resizable columns |
children | React.ReactNode | (values: ColumnRenderProps) => React.ReactNode | - | Column content or render prop with sort direction |
Table.Body Props
Inherits from React Aria TableBody.
| Prop | Type | Default | Description |
|---|---|---|---|
items | T[] | - | Dynamic row data for render prop pattern |
renderEmptyState | () => React.ReactNode | - | Content to display when the table is empty |
children | React.ReactNode | (item: T) => React.ReactNode | - | Static rows or render prop |
Table.Row Props
Inherits from React Aria Row.
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | number | - | Row identifier |
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Row cells |
Table.Cell Props
Inherits from React Aria Cell.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Cell content |
Table.Footer Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Footer content (e.g., pagination) |
Table.ColumnResizer Props
Inherits from React Aria ColumnResizer.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
Table.ResizableContainer Props
Inherits from React Aria ResizableTableContainer.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Table.Content element |
Table.LoadMore Props
Inherits from React Aria TableLoadMoreItem.
| Prop | Type | Default | Description |
|---|---|---|---|
isLoading | boolean | false | Whether data is currently loading |
onLoadMore | () => void | - | Handler called when the sentinel row is visible |
children | React.ReactNode | - | Loading indicator content |
Table.LoadMoreContent Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
children | React.ReactNode | - | Loading indicator content (e.g., Spinner) |
Table.Collection Props
Re-exported from React Aria Collection. Used to render dynamic cells within rows alongside static cells (e.g., checkboxes).
| Prop | Type | Default | Description |
|---|---|---|---|
items | T[] | - | Collection items |
children | (item: T) => React.ReactNode | - | Render prop for each item |
TableLayout
| Name | Type | Default | Description |
|---|---|---|---|
rowHeight | number | undefined | 48 | The fixed height of a row in px. |
estimatedRowHeight | number | undefined | — | The estimated height of a row, when row heights are variable. |
headingHeight | number | undefined | 48 | The fixed height of a section header in px. |
estimatedHeadingHeight | number | undefined | — | The estimated height of a section header, when the height is variable. |
loaderHeight | number | undefined | 48 | The fixed height of a loader element in px. This loader is specifically for "load more" elements rendered when loading more rows at the root level or inside nested row/sections. |
dropIndicatorThickness | number | undefined | 2 | The thickness of the drop indicator. |
gap | number | undefined | 0 | The gap between items. |
padding | number | undefined | 0 | The padding around the list. |


