diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fff810..2c05c93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Ensure correct order when conditionally rendering `Menu.Item`, `Listbox.Option` and `RadioGroup.Option` ([#1045](https://github.com/tailwindlabs/headlessui/pull/1045)) +- Improve controlled Tabs behaviour ([#1050](https://github.com/tailwindlabs/headlessui/pull/1050)) ## [Unreleased - @headlessui/vue] diff --git a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx index 420eb78..b58f138 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx @@ -551,6 +551,12 @@ describe('Rendering', () => { // test controlled behaviour await click(getByText('setSelectedIndex')) assertTabs({ active: 2 }) + + // test uncontrolled behaviour again + await click(getByText('Tab 2')) + expect(handleChange).toHaveBeenCalledTimes(2) + expect(handleChange).toHaveBeenNthCalledWith(2, 1) + assertTabs({ active: 1 }) }) it('should jump to the nearest tab when the selectedIndex is out of bounds (-2)', async () => { diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx index 0c0e585..5e057e5 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx @@ -202,6 +202,10 @@ function Tabs( }, [defaultIndex, selectedIndex, state.tabs, state.selectedIndex]) let lastChangedIndex = useRef(state.selectedIndex) + useEffect(() => { + lastChangedIndex.current = state.selectedIndex + }, [state.selectedIndex]) + let providerBag = useMemo>( () => [ state, diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts index f86e7d3..e4573d0 100644 --- a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts +++ b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts @@ -579,6 +579,12 @@ describe('`selectedIndex`', () => { // test controlled behaviour await click(getByText('setSelectedIndex')) assertTabs({ active: 2 }) + + // test uncontrolled behaviour again + await click(getByText('Tab 2')) + expect(handleChange).toHaveBeenCalledTimes(2) + expect(handleChange).toHaveBeenNthCalledWith(2, 1) + assertTabs({ active: 1 }) }) it('should jump to the nearest tab when the selectedIndex is out of bounds (-2)', async () => {