Components
- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input OTP
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
- New Component
Elements
Charts
Icons
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { invoices } from "@/data/table";
export const TableDemo = () => (
<Table>
<TableCaption>A list of 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.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
);For a sortable, filterable table with pagination and row selection, see the Data Table element built on top of this primitive.
Props
Table
Wraps the <table> element in a horizontally-scrollable container. All native <table> attributes are supported.
TableHead
| Prop | Description |
|---|---|
className | Forwarded to <th>. Use to set column width (className="w-[100px]") or alignment (text-right) |
TableCell
| Prop | Description |
|---|---|
colSpan | Merge cells across columns — useful for "No results" empty state rows |
className | Forwarded to <td> |
Usage
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
<Table>
<TableCaption>A list of 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>Paid</TableCell>
<TableCell>Credit Card</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
</TableFooter>
</Table>Specs
# Mint — Table Specs
## Component
- name: table
- file: registry/mint/table.tsx
- installs to: components/ui/table.tsx
- dependencies: none
- registryDependencies: none
## What is it
A styled wrapper around native HTML table elements. Provides consistent spacing,
row hover and selection states, borders, and text sizing. Contains no sorting,
filtering, or pagination logic — pair with @tanstack/react-table for interactive
data tables (see the Data Table element).
## Visual identity
Minimal and data-focused. Thin border lines (--border) divide rows and sections;
muted backgrounds provide subtle hover and selection feedback without competing
with cell content. Text is set at sm (14px), keeping dense data legible.
## Design tokens
--muted: oklch(0.96 0.02 155) / oklch(0.2 0.03 155) — row hover + footer bg + selected row bg
--muted-foreground: oklch(0.52 0.06 155) / oklch(0.6 0.06 155) — TableHead label colour + TableCaption colour
--border: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%) — row dividers, header border-b, footer border-t
## Sub-components
- Table → scrollable container (div overflow-x-auto) wrapping <table w-full caption-bottom text-sm>
- TableHeader → <thead> — adds border-b to all child rows via [&_tr]:border-b
- TableBody → <tbody> — removes border from the last row via [&_tr:last-child]:border-0
- TableFooter → <tfoot> — border-t, bg-muted/50, font-medium; suppresses border on its last row
- TableRow → <tr> — border-b, transition-colors, hover:bg-muted/50, data-[state=selected]:bg-muted
- TableHead → <th> — h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-muted-foreground
- TableCell → <td> — p-2 align-middle
- TableCaption → <caption> — mt-4 text-sm text-muted-foreground
## States
- hover: TableRow background shifts to bg-muted/50 on pointer-over
- data-[state=selected]: TableRow background shifts to bg-muted (full opacity) — use for row selection
- transition-colors: TableRow colour changes animate via CSS transition
## Conventions
- Set column widths on TableHead: className="w-[100px]"
- Right-align numeric columns: add className="text-right" to both TableHead and TableCell in that column
- Always include an empty-state row: <TableCell colSpan={n} className="h-24 text-center">No results.</TableCell>
- TableFooter is optional — use exclusively for summary or totals rows
- TableCaption is optional — add for screen-reader context when no visible heading accompanies the table
- Checkbox columns: both TableHead and TableCell auto-remove right padding ([&:has([role=checkbox])]:pr-0) and vertically centre checkboxes ([&>[role=checkbox]]:translate-y-[2px]) — no extra className needed
- Row selection with @tanstack/react-table: set data-state={row.getIsSelected() && "selected"} on TableRow
- Sub-components expose data-slot attributes for CSS targeting: "table-container", "table", "table-header", "table-body", "table-footer", "table-row", "table-head", "table-cell", "table-caption"Installation
$ npx shadcn add \https://gin-design.vercel.app/table