Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions packages/demo/src/content/components/tabs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,38 @@ Use the `suffix` property to render any React component after a tab's label. Thi
/>
```

### Forwarding trigger props

Use the `triggerProps` field on an item to forward props onto that individual tab's trigger. This is useful for attaching event handlers to a specific tab — for example, warming a destination's data on hover or focus (prefetching) when the user shows intent toward that tab.

Any props are spread onto the trigger before the component's own `value` and styling, so tab selection and internal classes are never overridden, and a custom `className` is merged with the internal ones. Event handlers compose with the component's built-in behavior, so tab activation and keyboard navigation are unchanged.

```tsx
<Tabs
id="prefetch-tabs"
items={[
{
label: "Declarations",
value: "declarations",
content: <div>Declarations Content</div>,
triggerProps: {
onPointerEnter: () => prefetchDeclarations(),
onFocus: () => prefetchDeclarations(),
},
},
{
label: "Reviews",
value: "reviews",
content: <div>Reviews Content</div>,
triggerProps: {
onPointerEnter: () => prefetchReviews(),
onFocus: () => prefetchReviews(),
},
},
]}
/>
```

## Props

---
Expand All @@ -221,10 +253,11 @@ Use the `suffix` property to render any React component after a tab's label. Thi

Each item in the `items` array should have the following structure:

| Name | Description | Type | Default | Required |
| --------- | ------------------------------------------------------------ | ------------------------------ | ------- | -------- |
| `label` | Text label displayed on the tab trigger | `string` | - | ✅ |
| `value` | Unique value that identifies this tab | `string` | - | ✅ |
| `icon` | Icon to display alongside the label (Lucide name or element) | `React.ReactElement`, `string` | - | ❌ |
| `suffix` | Content rendered after the label (e.g. a badge or count) | `React.ReactNode` | - | ❌ |
| `content` | Content to display when this tab is active | `React.ReactNode` | - | ✅ |
| Name | Description | Type | Default | Required |
| -------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------- | -------- |
| `label` | Text label displayed on the tab trigger | `string` | - | ✅ |
| `value` | Unique value that identifies this tab | `string` | - | ✅ |
| `icon` | Icon to display alongside the label (Lucide name or element) | `React.ReactElement`, `string` | - | ❌ |
| `suffix` | Content rendered after the label (e.g. a badge or count) | `React.ReactNode` | - | ❌ |
| `content` | Content to display when this tab is active | `React.ReactNode` | - | ✅ |
| `triggerProps` | Props forwarded onto this tab's trigger (see [Forwarding trigger props](#forwarding-trigger-props)) | `Omit<ComponentPropsWithoutRef<typeof TabsTrigger>, "value">` | - | ❌ |
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@eqtylab/equality",
"description": "EQTYLab's component and token-based design system",
"homepage": "https://equality.eqtylab.io/",
"version": "2.3.1",
"version": "2.3.2",
"license": "Apache-2.0",
"keywords": [
"component library",
Expand Down
10 changes: 6 additions & 4 deletions packages/ui/src/components/tabs/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, type ComponentPropsWithoutRef } from 'react';
import { motion } from 'motion/react';

import { Icon } from '@/components/icon/icon';
Expand All @@ -19,6 +19,7 @@ interface TabsProps {
icon?: React.ReactElement | string;
suffix?: React.ReactNode;
content: React.ReactNode;
triggerProps?: Omit<ComponentPropsWithoutRef<typeof TabsTrigger>, 'value'>;
}[];
className?: string;
tabsListBackground?: 'transparent' | 'filled';
Expand Down Expand Up @@ -80,18 +81,19 @@ const Tabs = ({
isFilled ? styles['tabs-list--filled'] : styles['tabs-list--transparent']
)}
>
{items.map(({ label, value, icon, suffix }) => {
{items.map(({ label, value, icon, suffix, triggerProps }) => {
const isActive = activeTab === value;

return (
<TabsTrigger
{...triggerProps}
key={value}
value={value}
className={cn(
styles['tabs-trigger'],
isFilled ? styles['tabs-trigger--filled'] : styles['tabs-trigger--transparent']
isFilled ? styles['tabs-trigger--filled'] : styles['tabs-trigger--transparent'],
triggerProps?.className
)}
data-tour={`${value}-tab-overview`}
>
{renderIcon(icon)}
{label}
Expand Down
Loading