diff --git a/packages/@headlessui-react/src/components/focus-trap/focus-trap.test.tsx b/packages/@headlessui-react/src/components/focus-trap/focus-trap.test.tsx
index 7f43d5ccd9..054ed6d9b8 100644
--- a/packages/@headlessui-react/src/components/focus-trap/focus-trap.test.tsx
+++ b/packages/@headlessui-react/src/components/focus-trap/focus-trap.test.tsx
@@ -108,6 +108,50 @@ it('should warn when there is no focusable element inside the FocusTrap', async
spy.mockReset()
})
+it(
+ 'should not be possible to programmatically escape the focus trap (if there is only 1 focusable element)',
+ suppressConsoleLogs(async () => {
+ function Example() {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+ }
+
+ render()
+
+ await nextFrame()
+
+ let [a, b] = Array.from(document.querySelectorAll('input'))
+
+ // Ensure that input-b is the active element
+ assertActiveElement(b)
+
+ // Tab to the next item
+ await press(Keys.Tab)
+
+ // Ensure that input-b is still the active element
+ assertActiveElement(b)
+
+ // Try to move focus
+ a?.focus()
+
+ // Ensure that input-b is still the active element
+ assertActiveElement(b)
+
+ // Click on an element within the FocusTrap
+ await click(b)
+
+ // Ensure that input-b is the active element
+ assertActiveElement(b)
+ })
+)
+
it(
'should not be possible to programmatically escape the focus trap',
suppressConsoleLogs(async () => {
@@ -214,6 +258,56 @@ it('should restore the previously focused element, before entering the FocusTrap
assertActiveElement(document.getElementById('item-2'))
})
+it('should stay in the FocusTrap when using `tab`, if there is only 1 focusable element', async () => {
+ render(
+ <>
+
+
+
+
+
+ >
+ )
+
+ await nextFrame()
+
+ // Item A should be focused because the FocusTrap will focus the first item
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Next
+ await press(Keys.Tab)
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Next
+ await press(Keys.Tab)
+ assertActiveElement(document.getElementById('item-a'))
+})
+
+it('should stay in the FocusTrap when using `shift+tab`, if there is only 1 focusable element', async () => {
+ render(
+ <>
+
+
+
+
+
+ >
+ )
+
+ await nextFrame()
+
+ // Item A should be focused because the FocusTrap will focus the first item
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Previous (loop around!)
+ await press(shift(Keys.Tab))
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Previous
+ await press(shift(Keys.Tab))
+ assertActiveElement(document.getElementById('item-a'))
+})
+
it('should be possible tab to the next focusable element within the focus trap', async () => {
render(
<>
diff --git a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts
index c7996c7ee3..f3c4c58cef 100644
--- a/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts
+++ b/packages/@headlessui-vue/src/components/focus-trap/focus-trap.test.ts
@@ -227,6 +227,60 @@ it('should restore the previously focused element, before entering the FocusTrap
assertActiveElement(document.getElementById('item-2'))
})
+it('should stay in the FocusTrap when using `tab`, if there is only 1 focusable element', async () => {
+ renderTemplate({
+ template: html`
+
+
+
+
+
+
+
+ `,
+ })
+
+ await nextFrame()
+
+ // Item A should be focused because the FocusTrap will focus the first item
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Next
+ await press(Keys.Tab)
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Next
+ await press(Keys.Tab)
+ assertActiveElement(document.getElementById('item-a'))
+})
+
+it('should stay in the FocusTrap when using `shift+tab`, if there is only 1 focusable element', async () => {
+ renderTemplate({
+ template: html`
+
+
+
+
+
+
+
+ `,
+ })
+
+ await nextFrame()
+
+ // Item A should be focused because the FocusTrap will focus the first item
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Previous (loop around!)
+ await press(shift(Keys.Tab))
+ assertActiveElement(document.getElementById('item-a'))
+
+ // Previous
+ await press(shift(Keys.Tab))
+ assertActiveElement(document.getElementById('item-a'))
+})
+
it('should be possible to tab to the next focusable element within the focus trap', async () => {
renderTemplate(
html`