Table
A data table for displaying structured information in rows and columns.
Overview
Tables are built from compositional primitives that map directly to HTML table elements . Each primitive is a styled wrapper that accepts all native HTML attributes, giving you full control over layout, sizing, and responsiveness.
- TableContainer: Wraps the
<table>in a scrollable container with elevation styling. - TableHeader / TableBody / TableFooter: Semantic section wrappers (
<thead>,<tbody>,<tfoot>). - TableRow: A table row (
<tr>) that acceptsonClickfor clickable rows. - TableHead: A column header cell (
<th>) with atruncateprop for overflow control. - TableCell: A data cell (
<td>) with atruncateprop for overflow control.
Usage
Import the components:
import {
TableContainer,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@eqtylab/equality";Basic usage:
<TableContainer>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Alice Cooper</TableCell>
<TableCell>alice@example.com</TableCell>
</TableRow>
</TableBody>
</TableContainer>Variants
Default
Clickable Rows
Rows accept an onClick handler, which enables hover interactions.
Sortable Columns
Use <SortButton> inside <TableHead> cells to add interactive sort controls.
Usage
import {
SortButton,
TableContainer,
TableHeader,
TableRow,
TableHead,
} from "@eqtylab/equality";
<TableContainer>
<TableHeader>
<TableRow>
<TableHead>
<SortButton
field="name"
sortField={sortField}
sortDirection={sortDirection}
onSort={handleSort}
>
Name
</SortButton>
</TableHead>
</TableRow>
</TableHeader>
</TableContainer>;With Border
Use the border prop on TableContainer to apply an elevation-aware border with rounded corners. This should be added most places the table is used, except when it lives within a container that already has a border.
Usage
<TableContainer border>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>{/* rows */}</TableBody>
</TableContainer>Empty State
When there are no rows, render empty state content in a <TableCell> that spans all columns with colSpan.
Empty State with Custom Component
The empty state cell accepts any ReactNode, so you can use a custom component like EmptyTableState.
Sticky Header
Use the sticky prop on <TableHeader> to keep column headers visible while scrolling. The height of the <TableContainer> must be constrained for this to work as expected.
Usage
<TableContainer className="max-h-[400px]">
<TableHeader sticky>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>{/* rows */}</TableBody>
</TableContainer>Column Sizing
Use the tableLayout prop on TableContainer to control how column widths are calculated. Set explicit widths on <TableHead> cells using Tailwind classes.
Fixed Layout
With tableLayout="fixed", columns respect explicit widths exactly. This is the recommended approach when you need predictable column sizing.
Usage
<TableContainer tableLayout="fixed">
<TableHeader>
<TableRow>
<TableHead className="w-[30%]">Name</TableHead>
<TableHead className="w-[30%]">Email</TableHead>
<TableHead className="w-[100px]">Role</TableHead>
<TableHead className="w-[100px]">Status</TableHead>
<TableHead className="w-[60px]" />
</TableRow>
</TableHeader>
</TableContainer>Min and Max Width
Use min-w- or max-w- Tailwind classes on <TableHead> to constrain column sizes. min-w- works in both auto and fixed layouts. max-w- works best with the default auto layout.
{
/* Column won't shrink below 150px */
}
<TableHead className="min-w-[150px]">Description</TableHead>;
{
/* Column won't grow beyond 300px — pair with truncate */
}
<TableHead className="max-w-[300px]" truncate>
Email
</TableHead>;Shrink to Content
In the default auto layout, use w-[1%] to minimize a column to fit its content. The browser’s table algorithm ensures the column still renders at least as wide as its content, while giving all remaining space to other columns. This is useful for action columns or icon-only columns.
<TableHead className="w-[1%]">{/* Actions */}</TableHead>Truncation
Use the truncate prop on <TableHead> and <TableCell> to clip overflowing text with an ellipsis. This works best with tableLayout="fixed" and an explicit column width so the cell has a defined boundary to truncate against.
Usage
<TableContainer tableLayout="fixed">
<TableHeader>
<TableRow>
<TableHead className="w-[25%]">Name</TableHead>
<TableHead className="w-[40%]" truncate>
Email
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Alice Cooper</TableCell>
<TableCell truncate>alice.cooper.very.long.email@example.com</TableCell>
</TableRow>
</TableBody>
</TableContainer>Responsive Columns
Use container queries to show or hide columns based on the table’s container width. Wrap the table in a @container element and apply hidden @md:table-cell (or similar) to both the <TableHead> and <TableCell> for columns that should collapse.
Usage
<div className="@container">
<TableContainer>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead className="hidden @md:table-cell">Email</TableHead>
<TableHead className="hidden @lg:table-cell">Role</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Alice Cooper</TableCell>
<TableCell className="hidden @md:table-cell">
alice@example.com
</TableCell>
<TableCell className="hidden @lg:table-cell">Admin</TableCell>
<TableCell>
<Badge variant="success">Active</Badge>
</TableCell>
</TableRow>
</TableBody>
</TableContainer>
</div>Elevations
Sunken
Base (default)
Raised
Overlay
Props
TableContainer
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
elevation | Controls the shadow and background styling | sunken, base, raised, overlay | raised | ❌ |
tableLayout | Controls the CSS table-layout algorithm | auto, fixed | auto | ❌ |
border | Applies an elevation-aware border with rounded corners | boolean | false | ❌ |
TableHeader
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
sticky | Keeps the header visible while the table scrolls | boolean | false | ❌ |
TableRow
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
clickable | Applies hover and cursor interaction styles | boolean | false | ❌ |
TableHead
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
truncate | Clips overflowing content with an ellipsis | boolean | false | ❌ |
TableCell
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
truncate | Clips overflowing content with an ellipsis | boolean | false | ❌ |