Table

A responsive table component.

View as Markdown
A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit Card$300.00
Total$2,500.00
<Table>  <TableCaption>A list of your recent invoices.</TableCaption>  <TableHeader>    <TableRow>      <TableHead>Invoice</TableHead>      <TableHead>Status</TableHead>      <TableHead>Method</TableHead>      <TableHead sx={styles.end}>Amount</TableHead>    </TableRow>  </TableHeader>  <TableBody>    {invoices.map((row) => (      <TableRow key={row.invoice}>        <TableCell>{row.invoice}</TableCell>        <TableCell>{row.status}</TableCell>        <TableCell>{row.method}</TableCell>        <TableCell sx={styles.end}>{row.amount}</TableCell>      </TableRow>    ))}  </TableBody></Table>

Installation

$ npx shadcn@latest add @constella/table

Usage

import {  Table,  TableBody,  TableCaption,  TableCell,  TableHead,  TableHeader,  TableRow,} from "@/components/primitives/table";
<Table>  <TableCaption>A list of your recent invoices.</TableCaption>  <TableHeader>    <TableRow>      <TableHead>Invoice</TableHead>      <TableHead>Amount</TableHead>    </TableRow>  </TableHeader>  <TableBody>    <TableRow>      <TableCell>INV001</TableCell>      <TableCell>$250.00</TableCell>    </TableRow>  </TableBody></Table>

Composition

Table├── TableCaption├── TableHeader│   └── TableRow│       └── TableHead├── TableBody│   └── TableRow│       └── TableCell└── TableFooter    └── TableRow        └── TableCell

Size

Use the size prop on Table for denser rows, for data a reader scans rather than reads: logs, usage, runs.

A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
Total$2,500.00
<Table size="sm">…</Table>
SizeHeader heightCell padding
sm32px4px
default40px8px

Interactive

Set interactive={false} on Table for a reference table a reader only reads, like a props list: rows stop lighting on hover and press. Selected rows keep their fill.

<Table interactive={false}>…</Table>

Use TableFooter for a totals row.

A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
Total$2,500.00
<TableFooter>  <TableRow>    <TableCell colSpan={3}>Total</TableCell>    <TableCell sx={styles.end}>$2,500.00</TableCell>  </TableRow></TableFooter>

Actions

Put a Dropdown Menu in the last cell for row actions.

ProductPriceActions
Wireless Mouse$29.99
Mechanical Keyboard$129.99
USB-C Hub$49.99
<TableCell sx={styles.end}>  <DropdownMenu>    <DropdownMenuTrigger      render={<Button aria-label="Open menu" size="icon" variant="ghost" />}    >      <HugeiconsIcon icon={MoreHorizontalIcon} />    </DropdownMenuTrigger>    <DropdownMenuContent align="end">      <DropdownMenuItem>Edit</DropdownMenuItem>      <DropdownMenuItem color="danger">Delete</DropdownMenuItem>    </DropdownMenuContent>  </DropdownMenu></TableCell>

Selected Rows

Add data-state="selected" to a TableRow to mark it. See Checkbox for a table with a checkbox per row.

API Reference

Each part renders its HTML element (Table wraps the <table> in a scrolling container) and takes every prop of it, plus sx, applied last.