Table
Structured data display with rows and columns. Table is the look; DataTable is that same look with sorting, filtering and pagination wired in — use it for every table in the product.
@/components/ui/table · @/components/ui/data-tableFull live example
Table demo
Editable table with search, sort, inline editing, row selection, and all custom components integrated.
| ID | Status | Priority | Partner | Assignee |
|---|---|---|---|---|
| T7A3763 | Open | Normal | Banana Corp | AS |
| T63JK93 | In Review | Normal | Orange Ltd | CW |
| T733U67 | Open | Critical | Plum Logistics | AS |
| T9399A6 | Testing | High | Lemon Labs | DB |
| T999U37 | Done | Low | Apple Industries | CW |
Data Table
DataTable is this same Table with a brain — it renders Table internally, so the look is identical. You pass columns + data instead of writing rows by hand, and it handles sorting, filtering and pagination. Use this for every table in the product — plain Table only for static demo markup.@/components/ui/data-table
Click ID or Status to sort.
| Title | Priority | Assignee | Created | ||
|---|---|---|---|---|---|
| T7A3763 | Fix login redirect | Open | High | DA | 13.5.2026 |
| T7A3801 | Update ticket filters | In Progress | Normal | MK | 12.5.2026 |
| T7A3820 | Export to CSV | In Review | Low | JB | 11.5.2026 |
| T7A3855 | Mobile layout fix | Closed | Critical | DA | 10.5.2026 |
| T7A3870 | API rate limit issue | Blocked | High | MK | 09.5.2026 |
| T7A3902 | Dark mode polish | Done | Low | JB | 08.5.2026 |
Tinted header
headerTint puts the sticky header on bg-table-header— one step off the panel surface, the same surface as a search input sitting above the table. Lighter than the panel in dark mode, a touch darker in light mode. Use it where the table is a screen's main content (Business Partners list); leave it off for tables tucked inside a card or a detail panel.
| Title | Priority | Assignee | Created | ||
|---|---|---|---|---|---|
| T7A3763 | Fix login redirect | Open | High | DA | 13.5.2026 |
| T7A3801 | Update ticket filters | In Progress | Normal | MK | 12.5.2026 |
| T7A3820 | Export to CSV | In Review | Low | JB | 11.5.2026 |
| T7A3855 | Mobile layout fix | Closed | Critical | DA | 10.5.2026 |
| T7A3870 | API rate limit issue | Blocked | High | MK | 09.5.2026 |
| T7A3902 | Dark mode polish | Done | Low | JB | 08.5.2026 |
Empty state
| ID | Title | Status |
|---|---|---|
| No tickets found. Try adjusting your filters. | ||
Column definitions
| Pattern | Example |
|---|---|
| Simple string | { accessorKey: "title", header: "Title" } |
| Sortable header | header: ({ column }) => <Button onClick={() => column.toggleSorting(...)}>ID</Button> |
| Custom cell | cell: ({ row }) => <StatusBadge status={row.getValue("status")} /> |
| Computed cell | cell: ({ row }) => <span>{row.original.firstName} {row.original.lastName}</span> |
| Actions cell | cell: ({ row }) => <DropdownMenu>...</DropdownMenu> |
Props — DataTable
| Prop | Type | Description |
|---|---|---|
| columns | ColumnDef<T>[] | TanStack column definitions — controls header, cell, sorting |
| data | T[] | Row data array |
| emptyMessage | string | Message shown when data is empty |
| enableSorting | boolean | Enables column sort (default: true when columns use toggleSorting) |
| enableFiltering | boolean | Enables column text filter |
| enablePagination | boolean | Adds pagination controls below the table |
| onRowClick | (row: T) => void | Makes rows clickable — used by the Business Partners list |
| bordered | boolean | Draws the rounded outer border. false for tables inside a card/panel |
| resizable | boolean | Drag a column's right edge to resize (default true). Table grows into horizontal scroll; min 60px; not persisted |
| fillHeight | boolean | Fill a height-constrained parent and scroll inside it, header pinned. Used by the ticket table |
| headerTint | boolean | Tints the sticky header bg-table-header — one step off the panel surface, same as the search input above it. Default false (bg-card). Used by the Business Partners list |
Inline edit
Click any Partner cell to edit. Click 1 — selects (blue ring). Click 2 or Enter — enters edit mode directly in the cell.
| ID | Status | Partner — click to edit | Priority |
|---|---|---|---|
| T7A3763 | Open | Banana Corp | Normal |
| T63JK93 | In Review | Orange Ltd | Normal |
| T733U67 | Open | Plum Logistics | Critical |
| T9399A6 | Testing | Lemon Labs | High |
| T999U37 | Done | Apple Industries | Low |
Enter to save · Escape to cancel · click outside to save
Pattern demos
Two-line rows
title + subtitle — click either line to edit
| ID | Title | Status | Priority |
|---|---|---|---|
| THL-001 | Fix login redirect loop Bug in auth flow causing infinite redirect on mobile Safari | Open | High |
| THL-002 | Update ticket filter panel Date range + multi-select filters missing from sidebar | In Progress | Normal |
| THL-003 | Export tickets to CSV Include all visible columns, respect active filters | In Review | Low |
Tree data
grouped by department — click arrow to expand/collapse
| Title | Status | Priority |
|---|---|---|
BSM Department2 | ||
Fix login redirect loop | Open | High |
API rate limit on batch import | Blocked | High |
Thilo Department2 | ||
Update ticket filter panel | In Progress | Normal |
SLA countdown bar not rendering | In Progress | High |
Finance Department1 |
Expandable rows
click a row to expand — shows description + assignee
| Title | Status | Priority | |
|---|---|---|---|
| Fix login redirect loop | Open | High | |
| Update ticket filter panel | In Progress | Normal | |
| Export tickets to CSV | In Review | Low |
Ellipsis column
long text truncates with '...' — hover to see full content
| ID | Title | Description |
|---|---|---|
| THL-001 | Fix login redirect loop | Users on mobile Safari get stuck in an infinite redirect loop after the session cookie expires mid-session. Reproduced on iOS 17.2+. Auth team confirmed the issue. |
| THL-002 | Update ticket filter panel | The filter panel is missing date range support and multi-value selection for status and priority fields. Users can only filter by one value at a time, which is a major usability issue. |
| THL-003 | Export tickets to CSV | CSV export should include all visible columns and respect active filters. Delimiter should be configurable — semicolon for European locale, comma for US. |
Summary row
footer row with ticket count and status breakdown
| ID | Title | Status | Priority |
|---|---|---|---|
| THL-001 | Fix login redirect loop | Open | High |
| THL-002 | Update ticket filter panel | In Progress | Normal |
| THL-003 | Export tickets to CSV | In Review | Low |
| THL-004 | Mobile layout overflow fix | Closed | Critical |
| THL-005 | API rate limit on batch import | Blocked | High |
| 5 tickets total | Open: 1In Progress: 1In Review: 1Closed: 1Blocked: 1 | ||
Row drag sort
drag the ⠿ handle to reorder rows
| Title | Status | Priority | |
|---|---|---|---|
| ⠿ | Fix login redirect loop | Open | High |
| ⠿ | Update ticket filter panel | In Progress | Normal |
| ⠿ | Export tickets to CSV | In Review | Low |
| ⠿ | Mobile layout overflow fix | Closed | Critical |
ColSpan / RowSpan
colspan and rowspan for merged cells
colspan — "Dates" header spans Created + Updated columns
| ID | Title | Dates | Status | |
|---|---|---|---|---|
| Created | Updated | |||
| THL-001 | Fix login redirect | 13 May | 15 May | Open |
| THL-002 | Update filter panel | 12 May | 14 May | In Progress |
| THL-003 | Export to CSV | 11 May | 11 May | In Review |
rowspan — Department cell spans multiple rows
| Department | ID | Title | Status |
|---|---|---|---|
| BSM | THL-001 | Fix login redirect | Open |
| THL-005 | API rate limit issue | Blocked | |
| Thilo | THL-002 | Update filter panel | In Progress |
| THL-007 | SLA countdown bar | In Progress |
Grouped headers
two header rows — 'Dates' + 'Assignment' parent groups
| ID | Title | Dates | Assignment | Status | ||
|---|---|---|---|---|---|---|
| Created | Updated | Assignee | Department | |||
| THL-001 | Fix login redirect | 13 May | 15 May | Dragana V. | BSM | Open |
| THL-002 | Update filter panel | 12 May | 14 May | Marko K. | Thilo | In Progress |
| THL-003 | Export to CSV | 11 May | 11 May | Jovana B. | Finance | In Review |
Virtual list
10,000 rows — only visible rows are in the DOM
Nested table
click a row to reveal its activity log as a nested table
| Title | Status | Priority | |
|---|---|---|---|
| Fix login redirect loop | Open | High | |
| Update filter panel | In Progress | Normal | |
| Export to CSV | In Review | Low |
Image cell
hover over any photo to see a larger preview — works with any image URL
| Photo | Name | Role | Department | Status | Priority |
|---|---|---|---|---|---|
| Dragana V. | Design Lead | Design | Open | High | |
| Marko K. | Support Agent | Support | In Progress | Normal | |
| Jovana B. | QA Engineer | Tech | In Review | Low | |
| Stefan V. | Account Mgr | Finance | Blocked | Critical | |
| Ana P. | HR Manager | HR | Done | Low |
Table builder — admin
Partner | Status | Priority | Assignee | |
|---|---|---|---|---|
Banana Corp | Open | Normal | AS | |
Orange Ltd | In Review | Normal | CW | |
Plum Logistics | Open | Critical | AS | |
Lemon Labs | Testing | High | DB | |
Apple Industries | Done | Low | CW |
Click any column header to rename it. Use + in the header to add a column, + Add row to add a row.
Sub-components
| Component | Role |
|---|---|
| Table | Root — sets width, border-collapse, and the 14px table type scale |
| TableHeader | Wraps the header row group (<thead>) |
| TableBody | Wraps the data row group (<tbody>) |
| TableRow | A single row — add hover:bg-muted/40 for interactivity |
| TableHead | Header cell (<th>) — text-[10px] uppercase pattern |
| TableCell | Data cell (<td>) |
| TableFooter | Summary row group — totals, pagination |
On this page