Component Architecture
Table Primitives
All tables use styled HTML primitives from @/components/ui/Table.tsx. These replace HeroUI's <Table> component which used a rigid React Aria collection system that enforced cell counts at the element level, breaking fragment-based row composition.
Available Components
| Component | Element | Purpose |
|---|---|---|
TableWrapper | <div> | Glass card wrapper with border, blur, shadow, rounded corners |
Table | <table> | Base table with border-collapse, optional fixed layout |
TableHead | <thead> | Header section (transparent row backgrounds) |
TableBody | <tbody> | Body section |
TableFooter | <tfoot> | Footer section |
TableRow | <tr> | Row with hover state and divider border |
TableHeaderCell | <th> | Sticky, glassy header cell with sort indicator support |
TableCell | <td> | Data cell with compact and truncate options |
TableLoading | <tr> | Full-width loading spinner row |
TableEmpty | <tr> | Full-width empty state row |
Usage
import {
TableWrapper,
Table,
TableHead,
TableBody,
TableRow,
TableHeaderCell,
TableCell,
} from '@/components/ui/Table';
<TableWrapper>
<Table aria-label="Example">
<TableHead>
<TableRow>
<TableHeaderCell sortable sorted="asc" onSort={handleSort}>
Name
</TableHeaderCell>
<TableHeaderCell>Status</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>Arthas</TableCell>
<TableCell>Active</TableCell>
</TableRow>
</TableBody>
</Table>
</TableWrapper>;
Sticky Headers + Horizontal Scroll
Both work when the scroll container uses overflow: auto in both directions. The <th> elements use position: sticky; top: 0 within that same scroll context.
<div className="h-[500px] overflow-auto">
<Table>
<TableHead>...</TableHead>
<TableBody>...</TableBody>
</Table>
</div>
Do not put overflow-x-hidden or separate overflow wrappers between the sticky headers and the scroll container.
Handling Wide Content
<Table fixed>—table-fixedlayout constrains columns to available width. Set widths on<th>withclassName="w-[200px]".<TableCell truncate>— clips text with ellipsis viatext-overflow: ellipsis.- Responsive hiding — use
className="hidden md:table-cell"on both<th>and<td>to hide columns on small screens.
Fragment Row Components
Unlike HeroUI's collection system, plain HTML tables support fragment-based row components:
function MemberRow({ member }) {
return (
<>
<TableCell>{member.name}</TableCell>
<TableCell>{member.role}</TableCell>
</>
);
}
// Works fine — fragments flatten into the <tr>
<TableRow>
<MemberRow member={m} />
</TableRow>;
Styling
Header cells use HeroUI theme tokens for visual consistency:
- Background:
bg-default-100/50withbackdrop-blur-md backdrop-saturate-150 - Text:
text-foreground-500 text-tiny font-semibold uppercase - Corners:
first:rounded-l-lg last:rounded-r-lg
TableWrapper provides the glass card look: backdrop-blur-xl bg-content1/70 border-divider/80.
TanStack Table
@tanstack/react-table is installed for headless table logic (client-side sorting, filtering, pagination). The styled primitives handle rendering while TanStack handles data.