Table

Table

Styled wrappers around the native HTML table elements. The root scrolls horizontally on overflow, and rows support hover and selected states.

Playground

InvoiceMethodAmount
INV001Credit Card$250.00
INV002PayPal$150.00
INV003Bank Transfer$350.00
rows
footer
selectedRow
<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.

A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
<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.json

Usage

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.

ProductPrice
Wireless Mouse$29.99
Mechanical Keyboard$149.99
USB-C Hub$49.99
<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.

ComponentDescription
TableThe table element (data-slot="table"), wrapped in a scroll container div (data-slot="table-container") that handles horizontal overflow.
TableHeaderthead (data-slot="table-header") – header rows keep a soft bottom border and are excluded from hover highlighting.
TableBodytbody (data-slot="table-body") – removes the border from the last row.
TableFootertfoot (data-slot="table-footer") with a top border and medium font weight, for totals and summary rows.
TableRowtr (data-slot="table-row") – soft bottom border, bg-secondary hover highlight with rounded end cells, and a bg-muted state via data-state="selected".
TableHeadth (data-slot="table-head") – left-aligned, whitespace-nowrap header cell in accent-foreground; trailing padding is dropped when it contains a checkbox.
TableCelltd (data-slot="table-cell") – muted, ellipsis-truncated body cell; trailing padding is dropped when it contains a checkbox.
TableCaptioncaption (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.

Search documentation

Search the component docs