Sortable data table
Compare structured records with sortable columns.
pnpm dlx shadcn@latest add @uiarc/sortable-data-tableLive · keyboard ready
- Tabular records people sort and select, such as projects, invoices, or users.
- Tables that need Shift-click range selection and a count line with Clear.
- Use data-grid when people edit cells like a spreadsheet.
- Use timeline for chronological activity.
- Use reorderable-list when people set the order by hand.
Installation
Add Sortable data table with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/sortable-data-tableAdds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { SortableDataTable } from "@/registry/components/sortable-data-table/sortable-data-table"; const projects = [ { id: "p1", name: "Harbour", owner: "Maya", budget: 42000 }, { id: "p2", name: "Atlas", owner: "Leo", budget: 18500 },]; export function Projects() { return ( <SortableDataTable rows={projects} rowKey="id" caption="Projects" columns={[{ key: "name", label: "Name" }, { key: "owner", label: "Owner" }, { key: "budget", label: "Budget" }]} defaultSort={{ key: "name", direction: "asc" }} selectable itemName={{ one: "project", other: "projects" }} /> );}SortableDataTable
A generic table with sortable columns, optional row selection, and rows that glide when re-sorted.
PropTypeDefaultDescription
rowsRequiredT[]–Row objects.columnsRequired{ key: string; label: string; sortable?: boolean; render?: (value: unknown, row: T) => ReactNode; numeric?: boolean; width?: number | string }[]–Column definitions. Columns are sortable unless sortable is false; numeric is detected when every value is a number.rowKeyRequiredkeyof T | ((row: T) => string)–Stable key per row.captionstring"Data table"Table caption, used as its accessible name.emptyMessagestring"No rows to show"Shown when rows is empty.defaultSort{ key: string; direction: "asc" | "desc" }–Sort applied on first render.onSortChange(sort: SortState) => void–Called when a header is pressed.selectablebooleanfalseAdds a checkbox column, row click selection, and a count line with Clear.selectedKeysstring[]–Controlled selection.defaultSelectedKeysstring[]–Initial selection when uncontrolled.onSelectionChange(keys: string[]) => void–Called with the new selection.itemName{ one: string; other: string }{ one: "row", other: "rows" }Noun for the count line, as in "6 projects".- ArrowLeftorArrowRight
- Moves between sortable headers.
- ArrowUporArrowDown
- Moves between row checkboxes; down from Select all enters the rows.
- HomeorEnd
- Jumps to the first or last header or row checkbox.
- EnterorSpace
- Sorts by a header or toggles a checkbox.
- Shift+click
- Selects a range of rows.
- Escape
- Clears the selection.
- A native table with caption, scoped headers, and aria-sort on sortable columns.
- Sort buttons are labelled like "Sort by Budget, currently ascending"; the select all checkbox shows a mixed state.
- Sort and selection changes are announced through a role="status" region.
- Rows glide to their new positions on a spring when the sort changes; the sort arrow flips.
- The selection count rolls and Clear fades in with a short blur.
- Reduced motion reorders instantly and fades the count.
- Wider layouts scroll horizontally inside the table instead of the page.
- Below 620px each row folds into two lines, and the header becomes a scrolling strip of sort buttons with Select all pinned.
- Hover row fills apply only on hover-capable fine pointers.
- Rows are not virtualized and each uses position layout animation for re-sorts; paginate long lists with pagination.
- Sorting runs client side over the rows you pass.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for tabular records people sort and select. Use timeline for chronological activity and a plain list for simple items.
- Sorting is client side over the given rows; for server sorting, control defaultSort per fetch and page with pagination.
- Use render for badges, avatars, or formatted numbers inside cells.
The full library index for assistants is at /llms.txt.