Table
A structured data table built from semantic HTML elements. Supports headers, body rows, an optional footer for summaries, and an optional caption. No sorting or pagination built in — compose those separately.
Anatomy
<Table> is the scrollable wrapper around a <table>. TableHeader wraps the <thead> section. TableBody wraps <tbody>. TableFooter wraps <tfoot> for summary rows. TableRow is a <tr>, TableHead a <th>, and TableCell a <td>. TableCaption renders an accessible caption above the table.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
Examples
Full table — header, body, footer
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Overdue | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| Total | $1,200.00 | ||
With caption
| Invoice | Method | Amount |
|---|---|---|
| INV001 | Credit Card | $250.00 |
| INV002 | PayPal | $150.00 |
| INV003 | Bank Transfer | $350.00 |
Design Guidelines
Do
- Right-align numeric columns. Numbers are easier to compare when they share the same right edge — use
className="text-right"on both the header and cells. - Use TableFooter for totals. Summary rows belong in
<tfoot>— this is semantically correct and visually distinct. - Add a TableCaption for data tables. Captions improve accessibility — screen readers announce them before reading the table.
Don't
- Don't put too many columns on mobile. Tables don't reflow — wrap them in a scroll container or hide less important columns at small breakpoints.
- Don't use tables for layout. Tables are for structured data. Use CSS grid or flexbox for page layout.
- Don't skip the header row. Every data table needs a
TableHeader— it communicates column semantics to assistive technology.
Developer Reference
Accessibility
TableHeadrenders<th scope="col">— screen readers use this to associate header cells with data cells.TableCaptionrenders a<caption>element, which is announced before the table content by screen readers.- The
<Table>wrapper addsoverflow-x-autoso wide tables scroll horizontally rather than breaking the layout. - For sortable columns, add
aria-sortto the relevantTableHeadand update it on interaction.
Usage
import {
Table,
TableHeader,
TableBody,
TableFooter,
TableRow,
TableHead,
TableCell,
TableCaption,
} from "@/components/ui/table"
<Table>
<TableCaption>Recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((inv) => (
<TableRow key={inv.id}>
<TableCell className="font-medium">{inv.id}</TableCell>
<TableCell>{inv.status}</TableCell>
<TableCell className="text-right">{inv.amount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={2}>Total</TableCell>
<TableCell className="text-right">$1,200.00</TableCell>
</TableRow>
</TableFooter>
</Table>