Navigation and layout
Table
A presentational semantic table with two densities, a pinned header, grid lines, a composable caption, and a loading state.
Install
npx shadcn@latest add https://4af.selfsimilar.dev/r/table.jsonUsage
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
<Table>
<TableCaption>People</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Role</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{people.map((person) => (
<TableRow key={person.id}>
<TableCell>{person.name}</TableCell>
<TableCell>{person.role}</TableCell>
</TableRow>
))}
</TableBody>
</Table>API
Main exports: Table, TableCaption, TableHeader, TableBody, TableFooter, TableRow,
TableHead, TableCell
Native <table> semantics with the library's row rules, two densities, a pinned header, optional
grid lines, an optional caption, and a loading state.
This table has no controls and no state. For a checkbox column, a selection action row, column
sorting, or a per-row actions menu, install data-table, which composes these
parts.
Props
Table
The other parts take their native element's props and add nothing of their own.
sm is 36px rows, md is 44px; both use a 36px header.
Caption
TableCaption must be the first child, as a native <caption> must be. The visible caption is
centered below the scrolling table while the native one stays available to assistive technology.
<Table>
<TableCaption>Release history</TableCaption>
<TableHeader>{/* ... */}</TableHeader>
</Table>Loading
loading replaces the body's rows with placeholders and sets aria-busy. The header keeps its
labels. Placeholder rows take their shape from the header you wrote, so give the header the
columns you intend to render.
<Table loading={isLoading} loadingRows={8}>Layout
The table sits in a scroll container carrying the library's thin scrollbar; style it with
wrapperClassName. With bordered, the frame is drawn on that container.
The header needs a bounded height to pin to:
<Table wrapperClassName="max-h-80">Pinned header cells take bg-background. Pass another fill through className on TableHead
when the table sits on a raised surface.
Rules
Boundaries — under the header, over the footer, and the frame when bordered — are 1.5px at the
full border token. Separators between rows and columns are 1px at 60% of it.
A vertical rule belongs to the leading edge of the cell that starts the column, which is how a
column declines its own rule: data-table's checkbox and actions columns draw none.
Composing on top
useTableContext() returns size, bordered, stickyHeader, loading, loadingRows and
columns. useTableSection() returns "header" | "body" | "footer" — a row can't infer this,
since a <thead> and a <tbody> hold identical <tr>s.
With rowComponent, these are what data-table builds on. Reach for them if you are adding a
column of your own.