Skip to content

Tables

The table family covers the full surface for tabular data: nine primitive components that compose into a typed HTML table, plus a DataTable recipe layer that wires in row selection, sortable headers, a toolbar, and pagination at app level via TanStack Vue Table.

Source ships only primitives under grid/table/. There is no DataTable composite in VUEDA; TanStack Vue Table integrates at the consuming application level. The DataTable section below is a recipe: a documented composition of primitives and layout patterns that any app can adopt directly.

This page is the visual contract the default theme guarantees. Use it as the target spec when you re-skin. If a cell breaks after a customization, the change has crossed from skin into design language.

For the mechanics of overriding any of this, see Customize VUEDA Appearance. Values (color, dimension) belong in CSS tokens; compositions belong in theme keys.

Table

The root Table component renders a scrollable container div (Table container slot, default relative w-full overflow-auto) wrapping the <table> element (Table table slot, default w-full caption-bottom text-sm). The container does not include border or background by default; those come from the enclosing surface (typically a Card or a bordered wrapper the consumer provides).

Seven additional keys cover the inner elements: TableHeader (empty; the header row's cells carry the divider), TableBody ([&>tr:last-child>*]:border-b-0), TableFooter (bg-muted/50 font-medium [&>tr:first-child>*]:border-t-hairline), TableRow (hover:bg-accent/50 data-[state=selected]:bg-primary/[0.06] [&>*]:border-b-hairline transition-colors). Row dividers sit on the cells, not the <tr>, because the table uses the separated border model, which does not paint borders on rows or row groups. TableHead (h-10 px-2 text-left align-middle font-medium whitespace-nowrap), TableCell (p-2 align-middle whitespace-nowrap), TableCaption (text-muted-foreground mt-4 text-sm).

Density

Density is a design-system pattern applied above the primitive layer, not encoded in the default theme keys. Three row heights are defined: default (32 px), compact (28 px), and condensed (24 px). In practice, density is set by overriding the TableHead and TableCell class props at the table level, or by patching the theme keys for a given context. The demos below use class prop overrides to show each tier.

TableEmpty

TableEmpty is a full-width empty-state row. It renders a TableRow containing a TableCell (spanning via colspan) that centers a vertically padded content block. The two theme keys are TableEmpty root (p-4 whitespace-nowrap align-middle text-sm text-foreground) and content (flex items-center justify-center py-10). Consumer content goes in the default slot and is displayed as a flex column inside content.

Four canonical variants: empty (first-run, primary CTA), loading (spinner + message), error (destructive icon + retry CTA), and filtered-empty (no matches, clear-filters CTA).

DataTable recipe

DataTable is not a VUEDA source composite. TanStack Vue Table wires in at app level; the patterns below show how the Table primitives compose with a toolbar, filter chip rail, selection bar, and pagination footer. These elements are application-layer responsibilities, not theme keys. The recipe is a candidate for promotion to a future composite component.

Key design decisions reflected here: sortable column headers use aria-sort for accessibility and flip the sort icon to the left of numeric columns so the number column edge stays stable when sort toggles; in-row actions are hidden by default and revealed on row hover, focus, or selected state; the selection bar appears at accent tint to signal a system-level state distinct from hover.

Documents matching: server v3.0.0a1.post1client v3.0.0-alpha.2