Table

Virtualized data table that stays smooth at 10k+ rows, with sortable headers, row selection, column resize and reorder, and a sticky header. Minimal, reduced-motion-safe motion.

Data Table

index.tsx

10k virtualized rows with sortable headers, row selection, column resize and reorder.

10,000 rows
Email
Status

Install

$ bunx --bun shadcn add @beui/table

Editable Table

index.tsx

Edit cells inline and insert or delete rows and columns via border handles; the table re-renders from the updated data and column defs.

Click a cell to edit. Use the column and row handles to insert or delete.

Install

$ bunx --bun shadcn add @beui/table-editable

Async Table

index.tsx

Loads pages on demand — skeleton rows on first load, then infinite scroll via onEndReached as the virtualized list nears the bottom.

0 loadedLoading…
Name
Email
Role
Status
MRR

Install

$ bunx --bun shadcn add @beui/table-async

API Reference

data
T[]
columns
TableColumn<T>[]
getRowId?
((row: T, index: number) => string)

Stable id per row, required for correct selection across sorts. Defaults to row index.

selectable?
boolean

Render a leading checkbox column with select-all in the header.

false
selectedRowIds?
string[]
defaultSelectedRowIds?
string[]
onSelectionChange?
((ids: string[]) => void)
sort?
SortState | null
defaultSort?
SortState | null
null
onSortChange?
((sort: SortState | null) => void)
resizable?
boolean

Allow dragging the right edge of a header to resize that column.

false
minColumnWidth?
number

Minimum column width in px when resizing.

64
onColumnResize?
((key: string, width: number) => void)
reorderable?
boolean

Allow dragging a header grip to reorder columns.

false
onColumnOrderChange?
((keys: string[]) => void)
onCellEdit?
((rowId: string, columnKey: string, value: string) => void)

Called when an `editable` cell changes.

onColumnRename?
((columnKey: string, value: string) => void)

When set, non-sortable headers become editable inputs for the column name.

onInsertRow?
((index: number, position: InsertPosition) => void)

Enables the row menu (Insert before / after). Receives the target index.

onDeleteRow?
((rowId: string, index: number) => void)

Enables Delete in the row menu.

onInsertColumn?
((index: number, position: InsertPosition) => void)

Enables the column menu (Insert before / after). Receives the target column index.

onDeleteColumn?
((columnKey: string, index: number) => void)

Enables Delete in the column menu.

rowHeight?
number

Fixed row height in px — required for virtualization.

48
height?
number

Scroll viewport height in px.

440
overscan?
number

Rows rendered above/below the viewport.

10
onEndReached?
(() => void)

Fires when the viewport scrolls near the bottom — load the next page.

loading?
boolean

Currently fetching — shows skeleton rows and pauses `onEndReached`.

false
skeletonRows?
number

How many skeleton rows to show while loading more (default 3).

3
emptyState?
ReactNode
No data
className?
string

Updated