From 1ab895914b0085783ae9c5c7e2554bf5b2e7abcd Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Tue, 2 Jun 2026 14:45:49 -0400 Subject: [PATCH 1/2] improve table row clickable interactions - adds an href tag that operates as a native link - prevents the row from highlighting or activating when interactive elements within it are being used --- packages/demo/src/components/demo/table.tsx | 6 +-- .../demo/src/content/components/table.mdx | 15 ++++-- .../table/table-components.module.css | 26 +++++++++- .../src/components/table/table-components.tsx | 51 ++++++++++++++++--- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/packages/demo/src/components/demo/table.tsx b/packages/demo/src/components/demo/table.tsx index c1651dc..a0d0bdd 100644 --- a/packages/demo/src/components/demo/table.tsx +++ b/packages/demo/src/components/demo/table.tsx @@ -483,11 +483,7 @@ export const TableDemo = ({ - toggleRow(2) : undefined} - > + Charlie Brown charlie@example.com Viewer diff --git a/packages/demo/src/content/components/table.mdx b/packages/demo/src/content/components/table.mdx index e8e50d5..0b0c67a 100644 --- a/packages/demo/src/content/components/table.mdx +++ b/packages/demo/src/content/components/table.mdx @@ -69,7 +69,12 @@ Basic usage: ### Clickable Rows -Rows accept an `onClick` handler, which enables hover interactions. Use `data-state="selected"` to mark a row as selected. +Rows can be made interactive in two ways: + +- **`onClick`** — Pass a click handler for custom behavior (e.g., toggling selection state). +- **`href`** — Pass a URL to make the row navigable on click. This also adds keyboard accessibility (`Enter`/`Space` to activate) and proper ARIA semantics. Add an `hrefLabel` prop to tell screen reader users where the link will go. + +Both props enable hover interactions automatically. Use `data-state="selected"` to mark a row as selected. Try clicking a row below to toggle its selected state! @@ -310,6 +315,8 @@ Use [container queries](https://tailwindcss.com/docs/responsive-design#what-are- ### TableRow -| Name | Description | Type | Default | Required | -| ----------- | ------------------------------------------- | --------- | ------- | -------- | -| `clickable` | Applies hover and cursor interaction styles | `boolean` | `false` | ❌ | +| Name | Description | Type | Default | Required | +| ----------- | ----------------------------------------------------------- | --------- | ---------------- | -------- | +| `clickable` | Applies hover and cursor interaction styles | `boolean` | `false` | ❌ | +| `href` | URL to navigate to on click | `string` | — | ❌ | +| `hrefLabel` | Accessible label for the link (announced by screen readers) | `string` | `"View details"` | ❌ | diff --git a/packages/ui/src/components/table/table-components.module.css b/packages/ui/src/components/table/table-components.module.css index f3b9ee6..7762c83 100644 --- a/packages/ui/src/components/table/table-components.module.css +++ b/packages/ui/src/components/table/table-components.module.css @@ -64,7 +64,31 @@ --hover-darken: 50%; --hover-lighten: 50%; @apply cursor-pointer; - @apply hover:bg-mixed-light! dark:hover:bg-mixed-dark!; +} + +/* Prevent row from highlighting when the user hovers clickable tags in the table */ +.table-row--clickable:not([data-state='selected']):hover:not( + :has(button:hover, a:not(.table-row-link):hover) + ) { + @apply bg-mixed-light! dark:bg-mixed-dark!; +} + +/* Linked Row (stretched link pattern) */ + +.table-row--linked { + @apply relative; +} + +.table-row-link { + @apply absolute inset-0 z-10; +} + +.table-row--linked :is(button, a:not(.table-row-link)) { + @apply relative z-20; +} + +.table-row--linked:has(.table-row-link:focus-visible) { + @apply outline-brand-primary outline outline-2 outline-offset-[-2px]; } .table-body .table-row--clickable[data-state='selected'] { diff --git a/packages/ui/src/components/table/table-components.tsx b/packages/ui/src/components/table/table-components.tsx index 41837b3..5fc4789 100644 --- a/packages/ui/src/components/table/table-components.tsx +++ b/packages/ui/src/components/table/table-components.tsx @@ -59,14 +59,49 @@ TableFooter.displayName = 'TableFooter'; const TableRow = React.forwardRef< HTMLTableRowElement, - React.HTMLAttributes & { clickable?: boolean } ->(({ className, clickable, ...props }, ref) => ( - -)); + React.HTMLAttributes & { + clickable?: boolean; + href?: string; + hrefLabel?: string; + } +>( + ( + { className, clickable, href, hrefLabel = 'View details', children, onClick, ...props }, + ref + ) => { + const isClickable = clickable || !!href; + + const handleClick = (e: React.MouseEvent) => { + // Don't trigger row click if an interactive element was clicked + const target = e.target as HTMLElement; + if (target.closest('button, a:not([data-table-row-link])')) { + return; + } + onClick?.(e); + }; + + return ( + + {href && ( + + {hrefLabel} + + )} + {children} + + ); + } +); TableRow.displayName = 'TableRow'; const TableHead = React.forwardRef< From 01609bde7beb876ed56edfe942c2e21b88155b68 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Tue, 2 Jun 2026 14:46:21 -0400 Subject: [PATCH 2/2] 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 436a533..1cd9a49 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.9.0", + "version": "1.9.1", "license": "Apache-2.0", "keywords": [ "component library",