Table
Styled wrappers around the native HTML table elements. The root scrolls horizontally on overflow, and rows support hover and selected states.
Playground
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">INV001</TableCell>
<TableCell>Credit Card</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">INV002</TableCell>
<TableCell>PayPal</TableCell>
<TableCell className="text-right">$150.00</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">INV003</TableCell>
<TableCell>Bank Transfer</TableCell>
<TableCell className="text-right">$350.00</TableCell>
</TableRow>
</TableBody>
</Table>Preview
Compose the native table anatomy: TableHeader with TableHead cells, TableBody with TableRow and TableCell, and an optional TableCaption rendered below the table.
<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.status}</TableCell>
<TableCell>{invoice.method}</TableCell>
<TableCell className="text-right">{invoice.amount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/table.jsonUsage
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Sandeep</TableCell>
<TableCell>sandeepk@example.com</TableCell>
</TableRow>
</TableBody>
</Table>Selected rows
Set data-state="selected" on a TableRow to give it a persistent bg-muted highlight – pair it with a checkbox column when building selectable lists.
<Table>
<TableHeader>
<TableRow>
<TableHead>Product</TableHead>
<TableHead className="text-right">Price</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow data-state="selected">
<TableCell className="font-medium">Wireless Mouse</TableCell>
<TableCell className="text-right">$29.99</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
<TableCell className="text-right">$149.99</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">USB-C Hub</TableCell>
<TableCell className="text-right">$49.99</TableCell>
</TableRow>
</TableBody>
</Table>API reference
Every part is a thin wrapper around its native HTML element (table, thead, tbody, tfoot, tr, th, td, caption) – each accepts className plus all standard props of that element, so colSpan, rowSpan and friends work as usual. There are no variant props.
| Component | Description |
|---|---|
| Table | The table element (data-slot="table"), wrapped in a scroll container div (data-slot="table-container") that handles horizontal overflow. |
| TableHeader | thead (data-slot="table-header") – header rows keep a soft bottom border and are excluded from hover highlighting. |
| TableBody | tbody (data-slot="table-body") – removes the border from the last row. |
| TableFooter | tfoot (data-slot="table-footer") with a top border and medium font weight, for totals and summary rows. |
| TableRow | tr (data-slot="table-row") – soft bottom border, bg-secondary hover highlight with rounded end cells, and a bg-muted state via data-state="selected". |
| TableHead | th (data-slot="table-head") – left-aligned, whitespace-nowrap header cell in accent-foreground; trailing padding is dropped when it contains a checkbox. |
| TableCell | td (data-slot="table-cell") – muted, ellipsis-truncated body cell; trailing padding is dropped when it contains a checkbox. |
| TableCaption | caption (data-slot="table-caption") – muted description rendered below the table (caption-bottom). |
Styling hooks
Because the parts are semantic table elements, screen readers get the native table roles for free. Each part exposes a data-slot attribute (table-container, table, table-header, table-body, table-footer, table-row, table-head, table-cell, table-caption) for CSS overrides. Hover styling is applied only on devices that support hover, borders around a hovered row fade out for a card-like highlight, and rows containing an expanded trigger (aria-expanded) get a subtle bg-muted/50 tint.