diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index 6ce4c25..85e823d 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Ensure the main tree and parent `Dialog` components are marked as `inert` ([#2290](https://github.com/tailwindlabs/headlessui/pull/2290))
+- Fix nested `Popover` components not opening ([#2293](https://github.com/tailwindlabs/headlessui/pull/2293))
## [1.7.11] - 2023-02-15
diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx
index fb6d760..4f6c755 100644
--- a/packages/@headlessui-react/src/components/popover/popover.test.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx
@@ -2481,3 +2481,64 @@ describe('Mouse interactions', () => {
})
)
})
+
+describe('Nested popovers', () => {
+ it(
+ 'should be possible to nest Popover components and control them individually',
+ suppressConsoleLogs(async () => {
+ render(
+
+ Toggle A
+
+ Contents A
+
+ Toggle B
+
+ Contents B
+
+
+
+
+ )
+
+ // Verify that Popover B is not there yet
+ expect(document.querySelector('[data-testid="popover-b"]')).toBeNull()
+
+ // Open Popover A
+ await click(getByText('Toggle A'))
+
+ // Ensure Popover A is visible
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+
+ // Ensure Popover B is visible
+ assertPopoverPanel(
+ { state: PopoverState.InvisibleUnmounted },
+ document.querySelector(
+ '[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+
+ // Open Popover B
+ await click(getByText('Toggle B'))
+
+ // Ensure both popovers are open
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+ })
+ )
+})
diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx
index e14ae8a..96d9ad6 100644
--- a/packages/@headlessui-react/src/components/popover/popover.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.tsx
@@ -393,7 +393,12 @@ let Button = forwardRefWithAs(function Button {
if (isWithinPanel) return
diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md
index 5deee34..f3fc70e 100644
--- a/packages/@headlessui-vue/CHANGELOG.md
+++ b/packages/@headlessui-vue/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Ensure the main tree and parent `Dialog` components are marked as `inert` ([#2290](https://github.com/tailwindlabs/headlessui/pull/2290))
+- Fix nested `Popover` components not opening ([#2293](https://github.com/tailwindlabs/headlessui/pull/2293))
## [1.7.10] - 2023-02-15
diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts
index f048460..825f2b3 100644
--- a/packages/@headlessui-vue/src/components/popover/popover.test.ts
+++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts
@@ -2574,3 +2574,64 @@ describe('Mouse interactions', () => {
})
)
})
+
+describe('Nested popovers', () => {
+ it(
+ 'should be possible to nest Popover components and control them individually',
+ suppressConsoleLogs(async () => {
+ renderTemplate(html`
+
+ Toggle A
+
+ Contents A
+
+ Toggle B
+
+ Contents B
+
+
+
+
+ `)
+
+ // Verify that Popover B is not there yet
+ expect(document.querySelector('[data-testid="popover-b"]')).toBeNull()
+
+ // Open Popover A
+ await click(getByText('Toggle A'))
+
+ // Ensure Popover A is visible
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+
+ // Ensure Popover B is visible
+ assertPopoverPanel(
+ { state: PopoverState.InvisibleUnmounted },
+ document.querySelector(
+ '[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+
+ // Open Popover B
+ await click(getByText('Toggle B'))
+
+ // Ensure both popovers are open
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+ assertPopoverPanel(
+ { state: PopoverState.Visible },
+ document.querySelector(
+ '[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
+ ) as HTMLElement
+ )
+ })
+ )
+})
diff --git a/packages/@headlessui-vue/src/components/popover/popover.ts b/packages/@headlessui-vue/src/components/popover/popover.ts
index ff7a470..eb7d948 100644
--- a/packages/@headlessui-vue/src/components/popover/popover.ts
+++ b/packages/@headlessui-vue/src/components/popover/popover.ts
@@ -288,6 +288,11 @@ export let PopoverButton = defineComponent({
let closeOthers = groupContext?.closeOthers
let panelContext = usePopoverPanelContext()
+
+ // A button inside a panel will just have "close" functionality, no "open" functionality.
+ // However, if a `Popover.Button` is rendered inside a `Popover` which in turn is rendered
+ // inside a `Popover.Panel` (aka nested popovers), then we need to make sure that the button is
+ // able to open the nested popover.
let isWithinPanel = computed(() =>
panelContext === null ? false : panelContext.value === api.panelId.value
)