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
5 changes: 4 additions & 1 deletion packages/eds-core-react/src/components/Tabs/TabList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ const TabList = forwardRef<HTMLDivElement, TabListProps>(function TabsList(
'aria-controls': `${tabsId}-panel-${$index + 1}`,
active: isActive,
$index,
onClick: () => handleChange($index),
onClick: () =>
handleChange(
controlledActive !== undefined ? controlledActive : $index,
Copy link

Copilot AI Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic uses controlledActive which represents the currently active tab, not the clicked tab's value. This will always pass the current active tab instead of the clicked tab's value. Should use the individual tab's value prop or $index for the clicked tab.

Suggested change
controlledActive !== undefined ? controlledActive : $index,
childProps.value !== undefined ? childProps.value : $index,

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of controlledActive could be confusing. I believe controlledActive represent the individual tab's value and not the current active tab. Do you agree @FredrikMWold ?

Copy link
Contributor Author

@FredrikMWold FredrikMWold Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, i agree that controlledActive sounds like the currently active tab and not the value of the clicked tab.
The most straight forward name would be value or tabValue

Or to rename childProps to tabProps and just use tabProps.value

),
ref: tabRef,
})
}) ?? []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Variants } from './Tabs.types'
type State = {
variant: Variants
scrollable: boolean
handleChange: (index: number) => void
handleChange: (value: number | string) => void
activeTab: number | string
tabsId: string
tabsFocused: boolean
Expand Down
20 changes: 20 additions & 0 deletions packages/eds-core-react/src/components/Tabs/Tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,24 @@ describe('Tabs', () => {
expect(screen.getByTestId(tablist)).toBeDefined()
expect(screen.getByTestId(tabpanels)).toBeDefined()
})
it('Calls onChange with value when provided, otherwise index', () => {
const handleChange = jest.fn()
render(
<Tabs activeTab="overview" onChange={handleChange}>
<Tabs.List>
<Tabs.Tab value="overview">Overview</Tabs.Tab>
<Tabs.Tab value="details">Details</Tabs.Tab>
<Tabs.Tab>Plain</Tabs.Tab>
</Tabs.List>
</Tabs>,
)

fireEvent.click(screen.getByText('Details'))
expect(handleChange).toHaveBeenLastCalledWith('details')

fireEvent.click(screen.getByText('Plain'))
expect(handleChange).toHaveBeenLastCalledWith(2)

expect(handleChange).toHaveBeenCalledTimes(2)
})
})
2 changes: 1 addition & 1 deletion packages/eds-core-react/src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type TabsProps = {
/** The index of the active tab OR a string matching the value prop on the active tab */
activeTab?: number | string
/** The callback function for selecting a tab */
onChange?: (index: number) => void
onChange?: (value: number | string) => void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a breaking API change. Would be great if this was marked as such in the release note.

/** Sets the width of the tabs. Tabs can have a maximum width of 360px */
variant?: Variants
/** adds scrollbar if tabs overflow on non-touch devices */
Expand Down
Loading