Table

Semantic table primitives for tabular data with consistent Reva styling.

DateHouseholdAmountStatus
11 MarMcCallaghan Family · Josh-£4,500.00Failed
7 MarMcCallaghan Family · Gaby£419.00Executed
19 Dec 2025McCallaghan Family · Josh-£213.69Failed
7 MarMcCallaghan Family · Gaby£7,000.00Executed
7 MarMcCallaghan Family · Gaby£49.00Executed
<div className="w-full max-w-3xl">  <Table>    <TableHeader>      <TableRow>        <TableHead>Date</TableHead>        <TableHead>Household</TableHead>        <TableHead className="text-right">Amount</TableHead>        <TableHead>Status</TableHead>      </TableRow>    </TableHeader>    <TableBody>      <TableRow>        <TableCell>11 Mar</TableCell>        <TableCell>McCallaghan Family · Josh</TableCell>        <TableCell className="text-right tabular-nums text-red-500">-£4,500.00</TableCell>        <TableCell>          <Badge variant="subtle" intent="destructive">Failed</Badge>        </TableCell>      </TableRow>      <TableRow>        <TableCell>7 Mar</TableCell>        <TableCell>McCallaghan Family · Gaby</TableCell>        <TableCell className="text-right tabular-nums text-green-500">£419.00</TableCell>        <TableCell>          <Badge variant="subtle" intent="neutral">Executed</Badge>        </TableCell>      </TableRow>      <TableRow>        <TableCell>19 Dec 2025</TableCell>        <TableCell>McCallaghan Family · Josh</TableCell>        <TableCell className="text-right tabular-nums text-red-500">-£213.69</TableCell>        <TableCell>          <Badge variant="subtle" intent="destructive">Failed</Badge>        </TableCell>      </TableRow>      <TableRow>        <TableCell>7 Mar</TableCell>        <TableCell>McCallaghan Family · Gaby</TableCell>        <TableCell className="text-right tabular-nums text-green-500">£7,000.00</TableCell>        <TableCell>          <Badge variant="subtle" intent="neutral">Executed</Badge>        </TableCell>      </TableRow>      <TableRow>        <TableCell>7 Mar</TableCell>        <TableCell>McCallaghan Family · Gaby</TableCell>        <TableCell className="text-right tabular-nums text-green-500">£49.00</TableCell>        <TableCell>          <Badge variant="subtle" intent="neutral">Executed</Badge>        </TableCell>      </TableRow>    </TableBody>  </Table></div>

Usage

import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableFooter,
  TableHead,
  TableHeader,
  TableRow,
} from "@reva/ui";

Composition

Use the following composition to build a Table:

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

Examples

An Actions example (row menus with a dropdown) will be added after the Dropdown Menu component ships in @reva/ui.

Use TableFooter for summary rows or totals, and TableCaption to add descriptive text below the table.

A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
Total$850.00
<div className="w-full max-w-2xl">  <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>      <TableRow>        <TableCell className="font-medium">INV001</TableCell>        <TableCell>          <Badge>Paid</Badge>        </TableCell>        <TableCell>Credit Card</TableCell>        <TableCell className="text-right">$250.00</TableCell>      </TableRow>      <TableRow>        <TableCell className="font-medium">INV002</TableCell>        <TableCell>          <Badge variant="subtle" intent="neutral">Pending</Badge>        </TableCell>        <TableCell>PayPal</TableCell>        <TableCell className="text-right">$150.00</TableCell>      </TableRow>      <TableRow>        <TableCell className="font-medium">INV003</TableCell>        <TableCell>          <Badge variant="subtle" intent="neutral">Unpaid</Badge>        </TableCell>        <TableCell>Bank Transfer</TableCell>        <TableCell className="text-right">$350.00</TableCell>      </TableRow>    </TableBody>    <TableFooter>      <TableRow>        <TableCell colSpan={3}>Total</TableCell>        <TableCell className="text-right">$850.00</TableCell>      </TableRow>    </TableFooter>  </Table></div>

Within Card

Two patterns for Card-embedded tables:

  • Bleed<CardContent className="px-0!"> + <Table variant="embedded">. The subtle header band spans edge-to-edge and the first column aligns optically with the CardHeader title via inset. Use this when the table is the primary content of the Card. The ! important modifier is required because CardContent's group-data-[size=sm]/card:px-4 variant outranks a plain px-0 by CSS specificity on size="sm" Cards.
  • Contained<CardContent> (default padding) + <Table> (default variant). The table sits inside the CardContent padding with flush first/last columns. Use this when the table sits alongside other content.
Transactions
DateHouseholdAmountStatus
11 MarMcCallaghan Family · Josh-£4,500.00Failed
7 MarMcCallaghan Family · Gaby£419.00Executed
19 Dec 2025McCallaghan Family · Josh-£213.69Failed
7 MarMcCallaghan Family · Gaby£7,000.00Executed
7 MarMcCallaghan Family · Gaby£49.00Executed
<div className="w-full max-w-3xl">  <Card>    <CardHeader>      <CardTitle>Transactions</CardTitle>    </CardHeader>    <CardContent className="px-0!">      <Table variant="embedded">        <TableHeader>          <TableRow>            <TableHead>Date</TableHead>            <TableHead>Household</TableHead>            <TableHead className="text-right">Amount</TableHead>            <TableHead>Status</TableHead>          </TableRow>        </TableHeader>        <TableBody>          <TableRow>            <TableCell>11 Mar</TableCell>            <TableCell>McCallaghan Family · Josh</TableCell>            <TableCell className="text-right font-medium tabular-nums text-red-500">-£4,500.00</TableCell>            <TableCell>              <Badge variant="subtle" intent="destructive">Failed</Badge>            </TableCell>          </TableRow>          <TableRow>            <TableCell>7 Mar</TableCell>            <TableCell>McCallaghan Family · Gaby</TableCell>            <TableCell className="text-right font-medium tabular-nums text-green-500">£419.00</TableCell>            <TableCell>              <Badge variant="subtle" intent="neutral">Executed</Badge>            </TableCell>          </TableRow>          <TableRow>            <TableCell>19 Dec 2025</TableCell>            <TableCell>McCallaghan Family · Josh</TableCell>            <TableCell className="text-right font-medium tabular-nums text-red-500">-£213.69</TableCell>            <TableCell>              <Badge variant="subtle" intent="destructive">Failed</Badge>            </TableCell>          </TableRow>          <TableRow>            <TableCell>7 Mar</TableCell>            <TableCell>McCallaghan Family · Gaby</TableCell>            <TableCell className="text-right font-medium tabular-nums text-green-500">£7,000.00</TableCell>            <TableCell>              <Badge variant="subtle" intent="neutral">Executed</Badge>            </TableCell>          </TableRow>          <TableRow>            <TableCell>7 Mar</TableCell>            <TableCell>McCallaghan Family · Gaby</TableCell>            <TableCell className="text-right font-medium tabular-nums text-green-500">£49.00</TableCell>            <TableCell>              <Badge variant="subtle" intent="neutral">Executed</Badge>            </TableCell>          </TableRow>        </TableBody>      </Table>    </CardContent>  </Card></div>

Variants

Use variant="default" (the default) for standalone, page-level tables and for contained tables that sit inside a CardContent's own padding — flush first/last columns with a border under the header. Use variant="embedded" when the table bleeds edge-to-edge inside a Card (or sits inside an Item) — the subtle header band spans the full Card width and inset keeps the first column aligned with the CardHeader title.

Embedded (bleed)
ProductCategoryPrice
LaptopElectronics999.99
Desk ChairFurniture150.00
Default (contained)
ProductCategoryPrice
LaptopElectronics999.99
Desk ChairFurniture150.00
<div className="w-full max-w-3xl space-y-6">  <Card>    <CardHeader>      <CardTitle>Embedded (bleed)</CardTitle>    </CardHeader>    <CardContent className="px-0!">      <Table variant="embedded">        <TableHeader>          <TableRow>            <TableHead>Product</TableHead>            <TableHead>Category</TableHead>            <TableHead className="text-right">Price</TableHead>          </TableRow>        </TableHeader>        <TableBody>          <TableRow>            <TableCell>Laptop</TableCell>            <TableCell>Electronics</TableCell>            <TableCell className="text-right tabular-nums">999.99</TableCell>          </TableRow>          <TableRow>            <TableCell>Desk Chair</TableCell>            <TableCell>Furniture</TableCell>            <TableCell className="text-right tabular-nums">150.00</TableCell>          </TableRow>        </TableBody>      </Table>    </CardContent>  </Card>  <Card>    <CardHeader>      <CardTitle>Default (contained)</CardTitle>    </CardHeader>    <CardContent>      <Table>        <TableHeader>          <TableRow>            <TableHead>Product</TableHead>            <TableHead>Category</TableHead>            <TableHead className="text-right">Price</TableHead>          </TableRow>        </TableHeader>        <TableBody>          <TableRow>            <TableCell>Laptop</TableCell>            <TableCell>Electronics</TableCell>            <TableCell className="text-right tabular-nums">999.99</TableCell>          </TableRow>          <TableRow>            <TableCell>Desk Chair</TableCell>            <TableCell>Furniture</TableCell>            <TableCell className="text-right tabular-nums">150.00</TableCell>          </TableRow>        </TableBody>      </Table>    </CardContent>  </Card></div>

Inset

The inset prop controls the horizontal padding on the first and last column cells. Let the table bleed edge-to-edge with <CardContent className="px-0!">, then pair inset="default" (24px) with Card size="default" and inset="sm" (16px) with Card size="sm" so header labels and body cells align optically with the Card's own padding.

Default Card and table inset
ProductPrice
Laptop999.99
Desk Chair150.00
Small Card and table inset
ProductPrice
Laptop999.99
Desk Chair150.00
<div className="grid w-full max-w-5xl gap-6 md:grid-cols-2">  <Card>    <CardHeader>      <CardTitle>Default Card and table inset</CardTitle>    </CardHeader>    <CardContent className="px-0!">      <Table variant="embedded" inset="default">        <TableHeader>          <TableRow>            <TableHead>Product</TableHead>            <TableHead className="text-right">Price</TableHead>          </TableRow>        </TableHeader>        <TableBody>          <TableRow>            <TableCell>Laptop</TableCell>            <TableCell className="text-right tabular-nums">999.99</TableCell>          </TableRow>          <TableRow>            <TableCell>Desk Chair</TableCell>            <TableCell className="text-right tabular-nums">150.00</TableCell>          </TableRow>        </TableBody>      </Table>    </CardContent>  </Card>  <Card size="sm">    <CardHeader>      <CardTitle>Small Card and table inset</CardTitle>    </CardHeader>    <CardContent className="px-0!">      <Table variant="embedded" inset="sm">        <TableHeader>          <TableRow>            <TableHead>Product</TableHead>            <TableHead className="text-right">Price</TableHead>          </TableRow>        </TableHeader>        <TableBody>          <TableRow>            <TableCell>Laptop</TableCell>            <TableCell className="text-right tabular-nums">999.99</TableCell>          </TableRow>          <TableRow>            <TableCell>Desk Chair</TableCell>            <TableCell className="text-right tabular-nums">150.00</TableCell>          </TableRow>        </TableBody>      </Table>    </CardContent>  </Card></div>

Sticky first column

To freeze a column while the rest scroll horizontally, prefer the DataTable's columnPinning — it wires up TanStack's pinning state and renders the sticky offsets, occluding background, and divider for you. On the raw primitives (for a bespoke or non-DataTable table) it's a manual composition: sticky left-0 z-10 on the first TableHead and every first-column TableCell, an occluding background (an opaque bg-canvas or a backdrop-blur glass panel), and a border-rTable's scroll container handles the overflow (pair with scrollArea for the branded horizontal scrollbar).

Props

Each part forwards native HTML attributes for its element (for example colSpan on TableCell) plus className. Table wraps the <table> in a horizontal scroll container — native overflow-x-auto by default, or the Reva ScrollArea (branded, hover-revealed horizontal scrollbar) when scrollArea is set.

Table

PropTypeDefaultDescription
variant"default" | "embedded""default""default" — standalone, flush columns, border under header. "embedded" — subtle header band, inset first/last columns (Card/Item-embedded).
inset"none" | "xs" | "sm" | "default" | "lg""default" (when variant="embedded"); "none" (when variant="default")Horizontal padding on first/last column cells. Values map to 0 / 8 / 16 / 24 / 32px respectively.
scrollAreabooleanfalseSwap the native overflow-x-auto container for the Reva ScrollArea — the branded, hover-revealed horizontal scrollbar — for wide grids that scroll sideways.

Parts

ExportElementRole
TabletableRoot; scroll wrapper is a sibling div in the DOM.
TableHeadertheadColumn headers.
TableBodytbodyData rows.
TableFootertfootFooter rows (e.g. totals).
TableRowtrRow; supports data-state="selected" for selected styling.
TableHeadthHeader cell.
TableCelltdBody or footer cell.
TableCaptioncaptionAccessible table description.

Sortable filters, pagination, and column APIs belong in the Data Table component (TanStack Table on top of these primitives); they are intentionally out of scope for this page.

On this page