From d1ed2cb334a168bb07944a4372d9c48bc33b59b6 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Tue, 24 Mar 2026 19:01:06 -0400 Subject: [PATCH 1/6] Apply tabular-nums to badge component --- packages/ui/src/components/badge/badge.module.css | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ui/src/components/badge/badge.module.css b/packages/ui/src/components/badge/badge.module.css index 6c722b2..92dc3ea 100644 --- a/packages/ui/src/components/badge/badge.module.css +++ b/packages/ui/src/components/badge/badge.module.css @@ -5,6 +5,7 @@ @apply rounded-full; @apply flex items-center; @apply w-max; + @apply tabular-nums; } /* Size Variants */ From c4990896fdeb83e5f7ae51aa55fd3e0d56586833 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 25 Mar 2026 01:21:24 -0400 Subject: [PATCH 2/6] Initial table refactor Explicitly endorse the component-based table workflow over the data-based one for code clarity & styling ability Co-Authored-By: Claude --- packages/demo/src/components/demo/table.tsx | 525 +++++++++++++----- .../demo/src/content/components/table.mdx | 245 ++++++-- .../table/table-components.module.css | 18 + .../src/components/table/table-components.tsx | 47 +- .../ui/src/components/table/table.module.css | 9 - packages/ui/src/components/table/table.tsx | 7 +- 6 files changed, 638 insertions(+), 213 deletions(-) diff --git a/packages/demo/src/components/demo/table.tsx b/packages/demo/src/components/demo/table.tsx index 4821a4a..f97164e 100644 --- a/packages/demo/src/components/demo/table.tsx +++ b/packages/demo/src/components/demo/table.tsx @@ -4,7 +4,12 @@ import { EmptyTableState, IconButton, SortButton, - Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableHeader, + TableRow, } from "@eqtylab/equality"; interface TableDemoProps { @@ -14,7 +19,10 @@ interface TableDemoProps { | "with-border" | "with-sorter" | "empty-state" - | "empty-state-custom"; + | "empty-state-custom" + | "column-sizing" + | "truncation" + | "responsive"; elevation?: Elevation; } @@ -22,166 +30,395 @@ export const TableDemo = ({ variant = "default", elevation, }: TableDemoProps) => { - const columns = [ - { key: "name", content: "Name" }, - { key: "email", content: "Email" }, - { key: "role", content: "Role" }, - { key: "status", content: "Status" }, - { key: "actions", content: "" }, - ]; + if (variant === "column-sizing") { + return ( + + + + Name + Email + Role + Status + + + + + + Alice Cooper + alice@example.com + Admin + + Active + + + + + + + Bob Smith + bob@example.com + User + + Active + + + + + + + Charlie Brown + charlie@example.com + Viewer + + Inactive + + + + + + + + ); + } - const rows = [ - { - key: "1", - cells: [ - { key: "name", content: "Alice Cooper" }, - { key: "email", content: "alice@example.com" }, - { key: "role", content: "Admin" }, - { key: "status", content: Active }, - { - key: "actions", - content: , - }, - ], - ...(variant === "clickable" && { - onClick: () => console.log("Clicked row 1"), - }), - }, - { - key: "2", - cells: [ - { key: "name", content: "Bob Smith" }, - { key: "email", content: "bob@example.com" }, - { key: "role", content: "User" }, - { key: "status", content: Active }, - { - key: "actions", - content: , - }, - ], - ...(variant === "clickable" && { - onClick: () => console.log("Clicked row 2"), - }), - }, - { - key: "3", - cells: [ - { key: "name", content: "Charlie Brown" }, - { key: "email", content: "charlie@example.com" }, - { key: "role", content: "Viewer" }, - { - key: "status", - content: Inactive, - }, - { - key: "actions", - content: , - }, - ], - ...(variant === "clickable" && { - onClick: () => console.log("Clicked row 3"), - }), - }, - ]; + if (variant === "truncation") { + return ( + + + + Name + + Email + + Role + Status + + + + + + Alice Cooper + + alice.cooper.very.long.email.address@example.com + + Admin + + Active + + + + + + + Bob Smith + bob@example.com + User + + Active + + + + + + + Charlie Brown + + charlie.brown.another.really.long.address@longdomain.example.com + + Viewer + + Inactive + + + + + + + + ); + } - if (variant === "with-sorter") { - const sortColumns = [ - { - key: "name", - content: ( - {}} - > - Name - - ), - }, - { - key: "email", - content: ( - {}} - > - Email - - ), - }, - { - key: "role", - content: ( - {}} - > - Role - - ), - }, - { - key: "status", - content: ( - {}} - > - Status - - ), - }, - { key: "actions", content: "" }, - ]; + if (variant === "responsive") { + return ( +
+ + + + Name + Email + Role + Status + + + + + + Alice Cooper + + alice@example.com + + Admin + + Active + + + + + + + Bob Smith + + bob@example.com + + User + + Active + + + + + + + Charlie Brown + + charlie@example.com + + Viewer + + Inactive + + + + + + + +
+ ); + } - return ; + if (variant === "with-sorter") { + return ( + + + + + {}} + > + Name + + + + {}} + > + Email + + + + {}} + > + Role + + + + {}} + > + Status + + + + + + + + Alice Cooper + alice@example.com + Admin + + Active + + + + + + + Bob Smith + bob@example.com + User + + Active + + + + + + + Charlie Brown + charlie@example.com + Viewer + + Inactive + + + + + + + + ); } if (variant === "empty-state") { return ( -
+ className="overflow-hidden rounded-md border" + > + + + Name + Email + Role + Status + + + + + + + No data available + + + + ); } if (variant === "empty-state-custom") { return ( -
{}} - /> - } - /> + className="overflow-hidden rounded-md border" + > + + + Name + Email + Role + Status + + + + + + + {}} + /> + + + + ); } return ( -
+ className={ + variant === "with-border" + ? "overflow-hidden rounded-md border" + : undefined + } + > + + + Name + Email + Role + Status + + + + + console.log("Clicked row 1") + : undefined + } + > + Alice Cooper + alice@example.com + Admin + + Active + + + + + + console.log("Clicked row 2") + : undefined + } + > + Bob Smith + bob@example.com + User + + Active + + + + + + console.log("Clicked row 3") + : undefined + } + > + Charlie Brown + charlie@example.com + Viewer + + Inactive + + + + + + + ); }; diff --git a/packages/demo/src/content/components/table.mdx b/packages/demo/src/content/components/table.mdx index 5e4b682..0c830f7 100644 --- a/packages/demo/src/content/components/table.mdx +++ b/packages/demo/src/content/components/table.mdx @@ -9,64 +9,87 @@ import { ELEVATION } from "@eqtylab/equality"; ## Overview -The Table component displays structured data in rows and columns. It supports clickable rows, sortable column headers, bordered styling, elevation levels, and empty state messaging. Column and cell `content` accepts any `ReactNode`, allowing badges, buttons, and other components inline. +--- + +The Table is 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 `
` in a scrollable container with elevation styling. +- **TableHeader / TableBody / TableFooter:** Semantic section wrappers (``, ``, ``). +- **TableRow:** A table row (``) that accepts `onClick` for clickable rows. +- **TableHead:** A column header cell (`
`) with a `truncate` prop for overflow control. +- **TableCell:** A data cell (``) with a `truncate` prop for overflow control. ## Usage -Import the component: +--- + +Import the components: -```ts -import { Table } from "@eqtylab/equality"; +```tsx +import { + TableContainer, + TableHeader, + TableBody, + TableRow, + TableHead, + TableCell, +} from "@eqtylab/equality"; ``` -Basic usage with required properties: +Basic usage: ```tsx - + + + + Name + Email + + + + + Alice Cooper + alice@example.com + + + ``` ## Variants +--- + ### Default ### Clickable Rows -Rows accept an `onClick` handler, which applies hover and cursor styles. +Rows accept an `onClick` handler, which enables interaction styling. ### Sortable Columns -Use [``](/components/sort-button) in column headers to add interactive sort controls. +Use [``](/components/sort-button) inside `` cells to add interactive sort controls. #### Usage ```tsx -import { SortButton, Table } from "@eqtylab/equality"; - -
+ + + Name - ), - }, - ]} - rows={rows} -/>; + + + +; ``` ### With Border -Apply a border to tables with the `border` prop. This should be added most places `
` is used, except for when it lives within a different container which already has a border applied. +Apply a border to tables by adding `overflow-hidden rounded-md border` to the `TableContainer` className. This should be added most places the table is used, except when it lives within a container that already has a border. ### Empty State -When `rows` is empty and `emptyState` is provided, the table keeps column headers visible and renders the empty state content spanning all columns. +When there are no rows, render empty state content in a `` that spans all columns with `colSpan`. ### Empty State with Custom Component -The `emptyState` prop accepts any `ReactNode`, so you can pass a custom component like `EmptyTableState`. +The empty state cell accepts any `ReactNode`, so you can use a custom component like `EmptyTableState`. +## Column Sizing + +--- + +Use the `tableLayout` prop on `TableContainer` to control how column widths are calculated. Set explicit widths on `` cells using the `style` prop. + +### Fixed Layout + +With `tableLayout="fixed"`, columns respect explicit widths exactly. This is the recommended approach when you need predictable column sizing. + + + +#### Usage + +```tsx + + + + Name + Email + Role + Status + + + + +``` + +### Min and Max Width + +Use `style={{ minWidth }}` or `style={{ maxWidth }}` on `` to constrain column sizes. `minWidth` works in both `auto` and `fixed` layouts. `maxWidth` works best with the default `auto` layout. + +```tsx +{ + /* Column won't shrink below 150px */ +} +Description; + +{ + /* Column won't grow beyond 300px — pair with truncate */ +} + + Email +; +``` + +### Shrink to Content + +In the default `auto` layout, use `style={{ width: "1%" }}` to minimize a column to fit its content. This is useful for action columns or icon-only columns. + +```tsx +{/* Actions */} +``` + +## Truncation + +--- + +Use the `truncate` prop on `` and `` 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 + +```tsx + + + + Name + + Email + + + + + + Alice Cooper + alice.cooper.very.long.email@example.com + + + +``` + +## Responsive Columns + +--- + +Use [container queries](https://tailwindcss.com/docs/responsive-design#what-are-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 `` and `` for columns that should collapse. + + + +#### Usage + +```tsx +
+ + + + Name + Email + Role + Status + + + + + Alice Cooper + + alice@example.com + + Admin + + Active + + + + +
+``` + ## Elevations +--- + ### Sunken @@ -120,10 +264,23 @@ The `emptyState` prop accepts any `ReactNode`, so you can pass a custom componen ## Props -| Name | Description | Type | Default | Required | -| ------------ | ------------------------------------------------------------ | ------------------------------------- | ------- | -------- | -| `columns` | Column definitions with key, content, and optional className | `TableColumn[]` | | ✅ | -| `rows` | Row data with key, cells, and optional onClick/className | `TableRowData[]` | | ✅ | -| `border` | Adds a border and rounded corners around the table | `boolean` | `false` | ❌ | -| `elevation` | Controls the shadow and border elevation level | `sunken`, `base`, `raised`, `overlay` | `base` | ❌ | -| `emptyState` | Content rendered when rows is empty, spanning all columns | `ReactNode` | | ❌ | +--- + +### TableContainer + +| Name | Description | Type | Default | Required | +| ------------- | ------------------------------------------ | ------------------------------------- | ------- | -------- | +| `elevation` | Controls the shadow and background styling | `sunken`, `base`, `raised`, `overlay` | `base` | ❌ | +| `tableLayout` | Controls the CSS table-layout algorithm | `auto`, `fixed` | `auto` | ❌ | + +### 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` | ❌ | diff --git a/packages/ui/src/components/table/table-components.module.css b/packages/ui/src/components/table/table-components.module.css index ec303d5..5e783cd 100644 --- a/packages/ui/src/components/table/table-components.module.css +++ b/packages/ui/src/components/table/table-components.module.css @@ -35,6 +35,24 @@ @apply [&:has([role=checkbox])]:pr-0; } +/* Clickable Variant */ + +.table-row--clickable { + --mix-color: var(--color-brand-primary); + --hover-darken: 50%; + --hover-lighten: 50%; + @apply cursor-pointer; + @apply hover:bg-mixed-light! dark:hover:bg-mixed-dark!; + @apply data-[state=selected]:bg-mixed-light dark:data-[state=selected]:bg-mixed-dark; +} + +/* Truncate Variants */ + +.table-head--truncate, +.table-cell--truncate { + @apply max-w-0 overflow-hidden text-ellipsis whitespace-nowrap; +} + .table-caption { @apply text-text-secondary mt-4 text-sm; } diff --git a/packages/ui/src/components/table/table-components.tsx b/packages/ui/src/components/table/table-components.tsx index def0c2c..4c8ebc3 100644 --- a/packages/ui/src/components/table/table-components.tsx +++ b/packages/ui/src/components/table/table-components.tsx @@ -9,10 +9,16 @@ const tableElevationVariants = generateElevationVariants(styles, 'table', ELEVAT const TableContainer = React.forwardRef< HTMLTableElement, - React.HTMLAttributes & VariantProps ->(({ className, elevation = ELEVATION.RAISED, ...props }, ref) => ( + React.HTMLAttributes & + VariantProps & { tableLayout?: 'auto' | 'fixed' } +>(({ className, elevation = ELEVATION.RAISED, tableLayout, ...props }, ref) => (
-
+
)); TableContainer.displayName = 'Table'; @@ -41,26 +47,39 @@ const TableFooter = React.forwardRef< )); TableFooter.displayName = 'TableFooter'; -const TableRow = React.forwardRef>( - ({ className, ...props }, ref) => ( - - ) -); +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes & { clickable?: boolean } +>(({ className, clickable, ...props }, ref) => ( + +)); TableRow.displayName = 'TableRow'; const TableHead = React.forwardRef< HTMLTableCellElement, - React.ThHTMLAttributes ->(({ className, ...props }, ref) => ( -
+ React.ThHTMLAttributes & { truncate?: boolean } +>(({ className, truncate, ...props }, ref) => ( + )); TableHead.displayName = 'TableHead'; const TableCell = React.forwardRef< HTMLTableCellElement, - React.TdHTMLAttributes ->(({ className, ...props }, ref) => ( - + React.TdHTMLAttributes & { truncate?: boolean } +>(({ className, truncate, ...props }, ref) => ( + )); TableCell.displayName = 'TableCell'; diff --git a/packages/ui/src/components/table/table.module.css b/packages/ui/src/components/table/table.module.css index a8f9155..aa05c79 100644 --- a/packages/ui/src/components/table/table.module.css +++ b/packages/ui/src/components/table/table.module.css @@ -4,15 +4,6 @@ @apply shadow-sm; } -.table-row-clickable { - --mix-color: var(--color-brand-primary); - --hover-darken: 50%; - --hover-lighten: 50%; - @apply cursor-pointer; - @apply hover:bg-mixed-light! dark:hover:bg-mixed-dark!; - @apply data-[state=selected]:bg-mixed-light dark:data-[state=selected]:bg-mixed-dark; -} - .table-border { @apply border; @apply overflow-hidden rounded-md; diff --git a/packages/ui/src/components/table/table.tsx b/packages/ui/src/components/table/table.tsx index 58fd486..63e224c 100644 --- a/packages/ui/src/components/table/table.tsx +++ b/packages/ui/src/components/table/table.tsx @@ -39,6 +39,7 @@ interface TableProps extends VariantProps { className?: string; border?: boolean; emptyState?: React.ReactNode; + tableLayout?: 'auto' | 'fixed'; } const tableElevationVariants = generateElevationVariants(styles, 'table', ELEVATION.BASE); @@ -50,6 +51,7 @@ const Table = ({ border = false, elevation = ELEVATION.BASE, emptyState, + tableLayout, }: TableProps) => { const isEmpty = rows.length === 0; @@ -62,7 +64,7 @@ const Table = ({ className )} > - + {columns.map((column) => ( @@ -85,7 +87,8 @@ const Table = ({ {rows.map((row) => ( {row.cells.map((cell) => ( From 68915a91dedcb3b1823c636f0b480ee03058a523 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 25 Mar 2026 01:26:59 -0400 Subject: [PATCH 3/6] specify actions column width --- packages/demo/src/components/demo/table.tsx | 8 ++++---- packages/demo/src/content/components/table.mdx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/demo/src/components/demo/table.tsx b/packages/demo/src/components/demo/table.tsx index f97164e..0dcf193 100644 --- a/packages/demo/src/components/demo/table.tsx +++ b/packages/demo/src/components/demo/table.tsx @@ -242,7 +242,7 @@ export const TableDemo = ({ Status - + @@ -296,7 +296,7 @@ export const TableDemo = ({ Email Role Status - + @@ -325,7 +325,7 @@ export const TableDemo = ({ Email Role Status - + @@ -360,7 +360,7 @@ export const TableDemo = ({ Email Role Status - + diff --git a/packages/demo/src/content/components/table.mdx b/packages/demo/src/content/components/table.mdx index 0c830f7..0e10d4f 100644 --- a/packages/demo/src/content/components/table.mdx +++ b/packages/demo/src/content/components/table.mdx @@ -170,7 +170,7 @@ Use `style={{ minWidth }}` or `style={{ maxWidth }}` on `` to constra ### Shrink to Content -In the default `auto` layout, use `style={{ width: "1%" }}` to minimize a column to fit its content. This is useful for action columns or icon-only columns. +In the default `auto` layout, use `style={{ width: "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. ```tsx {/* Actions */} From 4cc348d376bf08497fa96ce21b1e5a7e8fb9b963 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 25 Mar 2026 01:40:42 -0400 Subject: [PATCH 4/6] Add tableheader sticky prop Co-Authored-By: Claude --- packages/demo/src/components/demo/table.tsx | 89 ++++++++++++++++++- .../demo/src/content/components/table.mdx | 32 +++++++ .../table/table-components.module.css | 4 + .../src/components/table/table-components.tsx | 17 ++-- 4 files changed, 136 insertions(+), 6 deletions(-) diff --git a/packages/demo/src/components/demo/table.tsx b/packages/demo/src/components/demo/table.tsx index 0dcf193..1c83668 100644 --- a/packages/demo/src/components/demo/table.tsx +++ b/packages/demo/src/components/demo/table.tsx @@ -22,7 +22,8 @@ interface TableDemoProps { | "empty-state-custom" | "column-sizing" | "truncation" - | "responsive"; + | "responsive" + | "sticky-header"; elevation?: Elevation; } @@ -197,6 +198,92 @@ export const TableDemo = ({ ); } + if (variant === "sticky-header") { + return ( + + + + Name + Email + Role + Status + + + + + {[ + { + name: "Alice Cooper", + email: "alice@example.com", + role: "Admin", + active: true, + }, + { + name: "Bob Smith", + email: "bob@example.com", + role: "User", + active: true, + }, + { + name: "Charlie Brown", + email: "charlie@example.com", + role: "Viewer", + active: false, + }, + { + name: "Diana Prince", + email: "diana@example.com", + role: "Admin", + active: true, + }, + { + name: "Eve Wilson", + email: "eve@example.com", + role: "User", + active: true, + }, + { + name: "Frank Castle", + email: "frank@example.com", + role: "Viewer", + active: false, + }, + { + name: "Grace Hopper", + email: "grace@example.com", + role: "Admin", + active: true, + }, + { + name: "Hank Pym", + email: "hank@example.com", + role: "User", + active: true, + }, + ].map((user) => ( + + {user.name} + {user.email} + {user.role} + + + {user.active ? "Active" : "Inactive"} + + + + + + + ))} + + + ); + } + if (variant === "with-sorter") { return ( diff --git a/packages/demo/src/content/components/table.mdx b/packages/demo/src/content/components/table.mdx index 0e10d4f..4623f64 100644 --- a/packages/demo/src/content/components/table.mdx +++ b/packages/demo/src/content/components/table.mdx @@ -122,6 +122,26 @@ The empty state cell accepts any `ReactNode`, so you can use a custom component +### Sticky Header + +Use the `sticky` prop on `` to keep column headers visible while scrolling. The height of the `` must be constrained for this to work as expected. + + + +#### Usage + +```tsx + + + + Name + Email + + + {/* rows */} + +``` + ## Column Sizing --- @@ -273,6 +293,18 @@ Use [container queries](https://tailwindcss.com/docs/responsive-design#what-are- | `elevation` | Controls the shadow and background styling | `sunken`, `base`, `raised`, `overlay` | `base` | ❌ | | `tableLayout` | Controls the CSS table-layout algorithm | `auto`, `fixed` | `auto` | ❌ | +### 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 | diff --git a/packages/ui/src/components/table/table-components.module.css b/packages/ui/src/components/table/table-components.module.css index 5e783cd..f052c32 100644 --- a/packages/ui/src/components/table/table-components.module.css +++ b/packages/ui/src/components/table/table-components.module.css @@ -13,6 +13,10 @@ @apply [&_tr]:border-b; } +.table-header--sticky { + @apply sticky top-0 z-10; +} + .table-body { @apply [&_tr:last-child]:border-0; } diff --git a/packages/ui/src/components/table/table-components.tsx b/packages/ui/src/components/table/table-components.tsx index 4c8ebc3..3c5656f 100644 --- a/packages/ui/src/components/table/table-components.tsx +++ b/packages/ui/src/components/table/table-components.tsx @@ -11,8 +11,11 @@ const TableContainer = React.forwardRef< HTMLTableElement, React.HTMLAttributes & VariantProps & { tableLayout?: 'auto' | 'fixed' } ->(({ className, elevation = ELEVATION.RAISED, tableLayout, ...props }, ref) => ( -
+>(({ className, style, elevation = ELEVATION.RAISED, tableLayout, ...props }, ref) => ( +
->(({ className, ...props }, ref) => ( - + React.HTMLAttributes & { sticky?: boolean } +>(({ className, sticky, ...props }, ref) => ( + )); TableHeader.displayName = 'TableHeader'; From 0457a92cee60f741847ab914c4061cfe876126b4 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 25 Mar 2026 12:59:26 -0400 Subject: [PATCH 5/6] Update table.mdx --- packages/demo/src/content/components/table.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/demo/src/content/components/table.mdx b/packages/demo/src/content/components/table.mdx index 4623f64..faf4a80 100644 --- a/packages/demo/src/content/components/table.mdx +++ b/packages/demo/src/content/components/table.mdx @@ -11,7 +11,7 @@ import { ELEVATION } from "@eqtylab/equality"; --- -The Table is 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. +Tables are built from compositional primitives that map directly to [HTML table elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table). Each primitive is a styled wrapper that accepts all native HTML attributes, giving you full control over layout, sizing, and responsiveness. - **TableContainer:** Wraps the `
` in a scrollable container with elevation styling. - **TableHeader / TableBody / TableFooter:** Semantic section wrappers (``, ``, ``). @@ -65,7 +65,7 @@ Basic usage: ### Clickable Rows -Rows accept an `onClick` handler, which enables interaction styling. +Rows accept an `onClick` handler, which enables hover interactions. From ccb8496f4d784d8dd9e925d8b2957d8d09dceaed Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 25 Mar 2026 13:07:12 -0400 Subject: [PATCH 6/6] Update package.json --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index 964112b..daf91ff 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,7 +2,7 @@ "name": "@eqtylab/equality", "description": "EQTYLab's component and token-based design system", "homepage": "https://equality.eqtylab.io/", - "version": "1.4.1", + "version": "1.5.0", "license": "Apache-2.0", "keywords": [ "component library",