Table
A structured data display with headers, rows, and optional sorting, selection, and actions.
Usage
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from '@acronis-platform/shadcn-uikit';Basic
A simple table with headers and rows.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const invoices = [
{
invoice: 'INV001',
paymentStatus: 'Paid',
totalAmount: '$250.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV002',
paymentStatus: 'Pending',
totalAmount: '$150.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV003',
paymentStatus: 'Unpaid',
totalAmount: '$350.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV004',
paymentStatus: 'Paid',
totalAmount: '$450.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV005',
paymentStatus: 'Paid',
totalAmount: '$550.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV006',
paymentStatus: 'Pending',
totalAmount: '$200.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV007',
paymentStatus: 'Unpaid',
totalAmount: '$300.00',
paymentMethod: 'Credit Card',
},
];
export function TableBasic() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">
{invoice.totalAmount}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
With Footer
Table including a footer row for totals or summaries.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
View sourceHide source
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const invoices = [
{
invoice: 'INV001',
paymentStatus: 'Paid',
totalAmount: '$250.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV002',
paymentStatus: 'Pending',
totalAmount: '$150.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV003',
paymentStatus: 'Unpaid',
totalAmount: '$350.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV004',
paymentStatus: 'Paid',
totalAmount: '$450.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV005',
paymentStatus: 'Paid',
totalAmount: '$550.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV006',
paymentStatus: 'Pending',
totalAmount: '$200.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV007',
paymentStatus: 'Unpaid',
totalAmount: '$300.00',
paymentMethod: 'Credit Card',
},
];
export function TableWithFooter() {
return (
<div className="rounded-md border">
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">
{invoice.totalAmount}
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
);
}
With Selection
Table with row selection checkboxes.
| Name | Role | Status | ||
|---|---|---|---|---|
| John Doe | john@example.com | Admin | Active | |
| Jane Smith | jane@example.com | User | Active | |
| Bob Johnson | bob@example.com | User | Inactive | |
| Alice Williams | alice@example.com | Editor | Active | |
| Charlie Brown | charlie@example.com | User | Active |
View sourceHide source
import * as React from 'react';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
import { Checkbox } from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableWithSelection() {
const [selectedRows, setSelectedRows] = React.useState<number[]>([]);
const toggleRow = (id: number) => {
setSelectedRows((prev) =>
prev.includes(id) ? prev.filter((rowId) => rowId !== id) : [...prev, id]
);
};
const toggleAll = () => {
setSelectedRows((prev) =>
prev.length === users.length ? [] : users.map((u) => u.id)
);
};
return (
<div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">
<Checkbox
checked={selectedRows.length === users.length}
onCheckedChange={toggleAll}
/>
</TableHead>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow
key={user.id}
data-state={selectedRows.includes(user.id) && 'selected'}
>
<TableCell>
<Checkbox
checked={selectedRows.includes(user.id)}
onCheckedChange={() => toggleRow(user.id)}
/>
</TableCell>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell>{user.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{selectedRows.length > 0 && (
<p className="mt-2 text-sm text-muted-foreground">
{selectedRows.length} row(s) selected
</p>
)}
</div>
);
}
With Actions
Table with action buttons in each row.
| Name | Role | Actions | |
|---|---|---|---|
| John Doe | john@example.com | Admin | |
| Jane Smith | jane@example.com | User | |
| Bob Johnson | bob@example.com | User | |
| Alice Williams | alice@example.com | Editor | |
| Charlie Brown | charlie@example.com | User |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
import { Button } from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableWithActions() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm">
Edit
</Button>
<Button variant="ghost" size="sm">
Delete
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
With Badges
Table cells containing badge components.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
import { Badge } from '@acronis-platform/shadcn-uikit/react';
const invoices = [
{
invoice: 'INV001',
paymentStatus: 'Paid',
totalAmount: '$250.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV002',
paymentStatus: 'Pending',
totalAmount: '$150.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV003',
paymentStatus: 'Unpaid',
totalAmount: '$350.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV004',
paymentStatus: 'Paid',
totalAmount: '$450.00',
paymentMethod: 'Credit Card',
},
{
invoice: 'INV005',
paymentStatus: 'Paid',
totalAmount: '$550.00',
paymentMethod: 'PayPal',
},
{
invoice: 'INV006',
paymentStatus: 'Pending',
totalAmount: '$200.00',
paymentMethod: 'Bank Transfer',
},
{
invoice: 'INV007',
paymentStatus: 'Unpaid',
totalAmount: '$300.00',
paymentMethod: 'Credit Card',
},
];
export function TableWithBadges() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>
<Badge
variant={
invoice.paymentStatus === 'Paid'
? 'default'
: invoice.paymentStatus === 'Pending'
? 'secondary'
: 'destructive'
}
>
{invoice.paymentStatus}
</Badge>
</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">
{invoice.totalAmount}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Compact
Table with reduced padding for denser layouts.
| ID | Name | Role | |
|---|---|---|---|
| 1 | John Doe | john@example.com | Admin |
| 2 | Jane Smith | jane@example.com | User |
| 3 | Bob Johnson | bob@example.com | User |
| 4 | Alice Williams | alice@example.com | Editor |
| 5 | Charlie Brown | charlie@example.com | User |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableCompact() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="h-8 px-2">ID</TableHead>
<TableHead className="h-8 px-2">Name</TableHead>
<TableHead className="h-8 px-2">Email</TableHead>
<TableHead className="h-8 px-2">Role</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell className="px-2 py-2">{user.id}</TableCell>
<TableCell className="px-2 py-2">{user.name}</TableCell>
<TableCell className="px-2 py-2">{user.email}</TableCell>
<TableCell className="px-2 py-2">{user.role}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Striped
Table with alternating row backgrounds.
| Name | Role | Status | |
|---|---|---|---|
| John Doe | john@example.com | Admin | Active |
| Jane Smith | jane@example.com | User | Active |
| Bob Johnson | bob@example.com | User | Inactive |
| Alice Williams | alice@example.com | Editor | Active |
| Charlie Brown | charlie@example.com | User | Active |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableStriped() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user, index) => (
<TableRow
key={user.id}
className={index % 2 === 0 ? 'bg-muted/50' : ''}
>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell>{user.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Empty
Table displaying an empty state message.
| Name | Role | Status | |
|---|---|---|---|
| No results. | |||
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
export function TableEmpty() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell colSpan={4} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
);
}
Scrollable
Table with horizontal scrolling for wide content.
| ID | Name | Role | Status | Department | Location | Phone | |
|---|---|---|---|---|---|---|---|
| 1 | John Doe | john@example.com | Admin | Active | Engineering | San Francisco | +1 (555) 123-4567 |
| 2 | Jane Smith | jane@example.com | User | Active | Engineering | San Francisco | +1 (555) 123-4567 |
| 3 | Bob Johnson | bob@example.com | User | Inactive | Engineering | San Francisco | +1 (555) 123-4567 |
| 4 | Alice Williams | alice@example.com | Editor | Active | Engineering | San Francisco | +1 (555) 123-4567 |
| 5 | Charlie Brown | charlie@example.com | User | Active | Engineering | San Francisco | +1 (555) 123-4567 |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableScrollable() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">ID</TableHead>
<TableHead className="min-w-[150px]">Name</TableHead>
<TableHead className="min-w-[200px]">Email</TableHead>
<TableHead className="min-w-[100px]">Role</TableHead>
<TableHead className="min-w-[100px]">Status</TableHead>
<TableHead className="min-w-[150px]">Department</TableHead>
<TableHead className="min-w-[150px]">Location</TableHead>
<TableHead className="min-w-[150px]">Phone</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell>{user.id}</TableCell>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell>{user.status}</TableCell>
<TableCell>Engineering</TableCell>
<TableCell>San Francisco</TableCell>
<TableCell>+1 (555) 123-4567</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Sortable
Table with sortable column headers.
| John Doe | john@example.com | Admin | Active |
| Jane Smith | jane@example.com | User | Active |
| Bob Johnson | bob@example.com | User | Inactive |
| Alice Williams | alice@example.com | Editor | Active |
| Charlie Brown | charlie@example.com | User | Active |
View sourceHide source
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
import { Button } from '@acronis-platform/shadcn-uikit/react';
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'User',
status: 'Active',
},
{
id: 3,
name: 'Bob Johnson',
email: 'bob@example.com',
role: 'User',
status: 'Inactive',
},
{
id: 4,
name: 'Alice Williams',
email: 'alice@example.com',
role: 'Editor',
status: 'Active',
},
{
id: 5,
name: 'Charlie Brown',
email: 'charlie@example.com',
role: 'User',
status: 'Active',
},
];
export function TableSortable() {
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>
<Button variant="ghost" size="sm" className="h-8 px-2">
Name ↕
</Button>
</TableHead>
<TableHead>
<Button variant="ghost" size="sm" className="h-8 px-2">
Email ↕
</Button>
</TableHead>
<TableHead>
<Button variant="ghost" size="sm" className="h-8 px-2">
Role ↕
</Button>
</TableHead>
<TableHead>
<Button variant="ghost" size="sm" className="h-8 px-2">
Status ↕
</Button>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell>{user.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
Expandable rows
Table rows can be expanded to reveal additional details without increasing table width.
| Date | Name |
|---|---|
| 2016-05-01 | Tom |
| 2016-05-02 | Bartholomew Roberts |
| 2016-05-03 | Petti |
| 2016-05-04 | Lakka |
| 2016-05-05 | Gunnar |
View sourceHide source
import { Fragment, useMemo, useState } from 'react';
import { Button } from '@acronis-platform/shadcn-uikit/react';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@acronis-platform/shadcn-uikit/react';
const records = [
{
id: '2016-05-01',
date: '2016-05-01',
name: 'Tom',
details:
'Tom has a longer description that can be shown only when this row is expanded.',
},
{
id: '2016-05-02',
date: '2016-05-02',
name: 'Bartholomew Roberts',
details: 'Bartholomew details with additional metadata and notes.',
},
{
id: '2016-05-03',
date: '2016-05-03',
name: 'Petti',
details: 'Petti details with extra data for expanded rows.',
},
{
id: '2016-05-04',
date: '2016-05-04',
name: 'Lakka',
details: 'Lakka details with additional context.',
},
{
id: '2016-05-05',
date: '2016-05-05',
name: 'Gunnar',
details: 'Gunnar details with expanded content.',
},
];
export function TableExpandableRows() {
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());
const allExpanded = useMemo(
() => expandedRows.size === records.length,
[expandedRows]
);
const toggleRow = (id: string) => {
setExpandedRows((prev) => {
const next = new Set(prev);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return next;
});
};
const toggleAllRows = () => {
setExpandedRows(
allExpanded ? new Set() : new Set(records.map((record) => record.id))
);
};
return (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Date</TableHead>
<TableHead>Name</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{records.map((record) => {
const expanded = expandedRows.has(record.id);
return (
<Fragment key={record.id}>
<TableRow>
<TableCell className="font-medium">
<Button
variant="ghost"
size="sm"
className="mr-2 h-7 w-7 p-0"
onClick={() => toggleRow(record.id)}
aria-label={
expanded
? `Collapse ${record.date}`
: `Expand ${record.date}`
}
>
{expanded ? '−' : '+'}
</Button>
{record.date}
</TableCell>
<TableCell>{record.name}</TableCell>
</TableRow>
{expanded && (
<TableRow className="hover:bg-transparent">
<TableCell
colSpan={2}
className="h-auto py-3 text-sm text-muted-foreground"
>
{record.details}
</TableCell>
</TableRow>
)}
</Fragment>
);
})}
<TableRow>
<TableCell colSpan={2} className="text-center">
<Button variant="link" size="sm" onClick={toggleAllRows}>
{allExpanded ? 'Collapse all rows' : 'Expand all rows'}
</Button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
);
}
API Reference
The Table is a compound component built from standard HTML table elements. Each sub-component (Table, TableHeader, TableBody, TableRow, TableHead, TableCell, TableFooter, TableCaption) extends its native HTML element props with consistent styling.