Prodular UI

Data display

Table

A data table with hairline rows, muted 13px headers, numeric alignment, selected rows and an optional sticky header.

npx prodular-ui add table

In a card

The card is the container. The table adds no box of its own and its edge columns line up with the card padding.

Invoices
Issued in the last 30 days
InvoiceCustomerStatusIssuedAmount
INV-2048Pinecrest HealthPaidOct 18, 2026$12,480.00
INV-2047Tidewater FreightPast dueOct 14, 2026$3,920.00
INV-2046Corvid LabsPaidOct 11, 2026$860.50
INV-2045Marlow and FinchFailedOct 09, 2026$2,150.00
INV-2044Halden AnalyticsScheduledOct 02, 2026$7,300.00
Total$26,710.50

Sticky header

Set a max height on the container and pass sticky to keep the header in view.

API requests
Live tail for the production key
TimeRequestEndpointStatusLatency
14:32:59req_3f9a2cGET/v1/invoices20084 ms
14:32:52req_3fb91bPOST/v1/usage200112 ms
14:31:45req_3fd80aGET/v1/customers20196 ms
14:31:38req_3ff6f9GET/v1/webhooks200241 ms
14:30:31req_4015e8PATCH/v1/events42938 ms
14:30:24req_4034d7GET/v1/invoices20067 ms
14:29:17req_4053c6POST/v1/usage5001,290 ms
14:29:10req_4072b5GET/v1/customers20073 ms
14:28:03req_4091a4GET/v1/webhooks20455 ms
14:28:-4req_40b093PATCH/v1/events200188 ms
14:27:-11req_40cf82GET/v1/invoices20091 ms
14:27:-18req_40ee71POST/v1/usage40446 ms
14:26:-25req_410d60GET/v1/customers20084 ms
14:26:-32req_412c4fGET/v1/webhooks200112 ms
14:25:-39req_414b3ePATCH/v1/events20196 ms
14:25:-46req_416a2dGET/v1/invoices200241 ms

Anatomy

<Card>  <CardHeader>    <CardTitle>Invoices</CardTitle>  </CardHeader>  <CardContent>    <Table>      <TableHeader>        <TableRow>          <TableHead>Customer</TableHead>          <TableHead numeric>Amount</TableHead>        </TableRow>      </TableHeader>      <TableBody>        <TableRow>          <TableCell>Pinecrest Health</TableCell>          <TableCell numeric>$12,480.00</TableCell>        </TableRow>      </TableBody>    </Table>  </CardContent></Card>

Guidance

Use it when

  • Records people scan, compare and act on: invoices, members, requests, deployments.
  • Put tables inside a Card with a title and the primary table action in CardAction.
  • Right align every numeric column, including its header, so digits line up.

Avoid

  • A border or a tinted wrapper around the table inside a card. The card is the only box.
  • Zebra striping. Hairline row dividers and hover are enough.
  • More than one badge or more than two lines of text per cell.

Rules for AI agents

Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.

  • Place Table directly inside CardContent. Do not wrap it in another bordered div. The edge padding aligns with the card automatically.
  • Pass numeric to both TableHead and TableCell for amounts, counts, durations and percentages.
  • Format currency with Intl.NumberFormat and put units in the cell (184 ms), not in a separate column.
  • Mark the selected row with data-state="selected" or aria-selected. Do not add your own background classes.
  • Use font-mono only for ids and hashes, never for names or dates.
  • For long tables, pass containerClassName="max-h-96" to Table and sticky to TableHeader.
  • Use Badge size="sm" inside cells.

API

Table

PropTypeDefaultDescription
containerClassNamestringClasses for the scrolling wrapper. Set a max height here for a sticky header.

TableHeader

PropTypeDefaultDescription
stickybooleanfalseKeeps the header row visible while the container scrolls.

TableHead

PropTypeDefaultDescription
numericbooleanfalseRight aligns the header to match numeric cells.

TableCell

PropTypeDefaultDescription
numericbooleanfalseRight aligns the cell with tabular figures.

TableRow

PropTypeDefaultDescription
data-state"selected"Highlights the row with the brand tint. aria-selected works too.