diff --git a/CHANGELOG.md b/CHANGELOG.md
index 12f58df..03ffda3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Stop the event from propagating in the `Popover` component ([#798](https://github.com/tailwindlabs/headlessui/pull/798))
- Allow to click on elements inside a `Dialog.Overlay` ([#816](https://github.com/tailwindlabs/headlessui/pull/816))
+- Ensure interactability with `Popover.Panel` contents when using the `static` prop ([#857](https://github.com/tailwindlabs/headlessui/pull/857))
## [Unreleased - Vue]
diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx
index 3df9c9b..ef1b208 100644
--- a/packages/@headlessui-react/src/components/popover/popover.test.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx
@@ -1,5 +1,5 @@
import React, { createElement, useEffect, useRef } from 'react'
-import { render } from '@testing-library/react'
+import { render, screen } from '@testing-library/react'
import { Popover } from './popover'
import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs'
@@ -2125,4 +2125,78 @@ describe('Mouse interactions', () => {
assertActiveElement(getPopoverButton())
})
)
+
+ it(
+ 'should not close the Popover when clicking on a focusable element inside a static Popover.Panel',
+ suppressConsoleLogs(async () => {
+ let clickFn = jest.fn()
+
+ render(
+
+ Open
+
+
+
+
+ )
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The button should not close the popover
+ await click(getByText('btn'))
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.Visible })
+
+ // Verify we actually clicked the button
+ expect(clickFn).toHaveBeenCalledTimes(1)
+ })
+ )
+
+ it(
+ 'should not close the Popover when clicking on a non-focusable element inside a static Popover.Panel',
+ suppressConsoleLogs(async () => {
+ render(
+
+ Open
+
+ element
+
+
+ )
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The element should not close the popover
+ await click(getByText('element'))
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.Visible })
+ })
+ )
+
+ it(
+ 'should close the Popover when clicking outside of a static Popover.Panel',
+ suppressConsoleLogs(async () => {
+ render(
+
+ Open
+
+ element
+
+
+ )
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The element should close the popover
+ await click(document.body)
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.InvisibleHidden })
+ })
+ )
})
diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx
index 9ddbf11..f0e7264 100644
--- a/packages/@headlessui-react/src/components/popover/popover.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.tsx
@@ -619,10 +619,12 @@ let Panel = forwardRefWithAs(function Panel {
+ if (props.static) return
+
if (state.popoverState === PopoverStates.Closed && (props.unmount ?? true)) {
dispatch({ type: ActionTypes.SetPanel, panel: null })
}
- }, [state.popoverState, props.unmount, dispatch])
+ }, [state.popoverState, props.unmount, props.static, dispatch])
// Move focus within panel
useEffect(() => {
diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts
index bc872cc..7ba73f6 100644
--- a/packages/@headlessui-vue/src/components/popover/popover.test.ts
+++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts
@@ -2323,4 +2323,81 @@ describe('Mouse interactions', () => {
assertActiveElement(getPopoverButton())
})
)
+
+ it(
+ 'should not close the Popover when clicking on a focusable element inside a static PopoverPanel',
+ suppressConsoleLogs(async () => {
+ let clickFn = jest.fn()
+
+ renderTemplate({
+ template: html`
+
+ Open
+
+
+
+
+ `,
+ setup: () => ({ clickFn }),
+ })
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The button should not close the popover
+ await click(getByText('btn'))
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.Visible })
+
+ // Verify we actually clicked the button
+ expect(clickFn).toHaveBeenCalledTimes(1)
+ })
+ )
+
+ it(
+ 'should not close the Popover when clicking on a non-focusable element inside a static PopoverPanel',
+ suppressConsoleLogs(async () => {
+ renderTemplate(html`
+
+ Open
+
+ element
+
+
+ `)
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The element should not close the popover
+ await click(getByText('element'))
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.Visible })
+ })
+ )
+
+ it(
+ 'should close the Popover when clicking outside of a static PopoverPanel',
+ suppressConsoleLogs(async () => {
+ renderTemplate(html`
+
+ Open
+
+ element
+
+
+ `)
+
+ // Open the popover
+ await click(getPopoverButton())
+
+ // The element should close the popover
+ await click(document.body)
+
+ // Verify it is still open
+ assertPopoverButton({ state: PopoverState.InvisibleHidden })
+ })
+ )
})