Data Table Variants
26 production-ready patterns — pick one, see the live preview, copy the code
Simple Contact List
Basic table with search and pagination — ideal starter.
Contacts
A simple list of contacts.
| Phone | ||
|---|---|---|
| Alice Johnson | alice@example.com | +1 555-0101 |
| Bob Smith | bob@example.com | +1 555-0102 |
| Carol White | carol@example.com | +1 555-0103 |
| David Brown | david@example.com | +1 555-0104 |
| Eva Martinez | eva@example.com | +1 555-0105 |
| Frank Lee | frank@example.com | +1 555-0106 |
| Grace Hop | grace@example.com | +1 555-0107 |
| Henry Ford | henry@example.com | +1 555-0108 |
Showing 1–8 of 8
Install & set up
Everything this table needs: 2 generated files to copy and 23 shared engine files the CLI can install for you.
Data Source
Choose how data is loaded — only the matching helpers are generated.
Install it with the CLI
Installs every file below and its packages in one command. The steps after this are only for doing it by hand.
npx afnoui add tables/tables-simple-listOr install the packages yourself
Only needed if you copied the files by hand instead of running the command above.
Runtime dependencies
npm install @radix-ui/react-avatar @radix-ui/react-checkbox @radix-ui/react-dropdown-menu @radix-ui/react-progress @radix-ui/react-radio-group @radix-ui/react-scroll-area @radix-ui/react-select @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-tooltip @tanstack/react-virtual class-variance-authority clsx lucide-react react tailwind-mergeDev dependencies
npm install -D @types/react typescriptGenerated files
Generated files are yours to copy and edit; shared engine files are installed once and reused.
Generated per table(2)
Shared engine — copy once(23)
Strongly-typed config object + Row interface for this table.
import type { TableBuilderConfig, TableRow } from "./types";
export interface Row extends TableRow {
id: string;
"name": string;
"email": string;
"phone": string;
}
export const tableConfig: TableBuilderConfig = {
"title": "Contacts",
"description": "A simple list of contacts.",
"direction": "ltr",
"density": "comfortable",
"pageSize": 8,
"sortMode": "client",
"paginationMode": "client",
"expandableLayout": "details",
"expandableIconStyle": "chevron",
"expandableIconPosition": "first",
"paginationLayout": "full",
"pageSizeOptions": [
5,
10,
20,
50,
100
],
"virtualRowHeight": 44,
"virtualMaxHeight": 520,
"enableDnD": false,
"enableHover": true,
"enableSearch": true,
"enableExport": false,
"enableFooter": false,
"enableStriped": false,
"enableBordered": false,
"enableMultiSort": false,
"enablePagination": true,
"enableInlineEdit": false,
"enableRowGrouping": false,
"enableBulkActions": false,
"enableAggregation": false,
"enableRowSelection": false,
"enableStickyHeader": false,
"enableColumnResize": false,
"enableColumnFilters": false,
"enableNestedHeaders": false,
"enablePinnedColumns": false,
"enableVirtualization": false,
"enableExpandableRows": false,
"enableColumnVisibility": false,
"columns": [
{
"id": "c1",
"key": "name",
"label": "Name",
"type": "text",
"sortable": true,
"filterable": true,
"visible": true,
"align": "left"
},
{
"id": "c2",
"key": "email",
"label": "Email",
"type": "email",
"sortable": true,
"filterable": true,
"visible": true,
"align": "left"
},
{
"id": "c3",
"key": "phone",
"label": "Phone",
"type": "text",
"sortable": false,
"filterable": false,
"visible": true,
"align": "left"
}
],
"stickyMaxHeight": 600
} as const satisfies TableBuilderConfig;