Add a quick trigger action to the Menu, Listbox and Combobox components (#3700)

This PR adds a new quick trigger feature to the `Menu`. Not sure what
the best
name for this is, but essentially this is the behavior:

Recently we made sure that the `Menu` opens on `mousedown` (not just
`click`).

This means that we can perform the following quick action:
1. `mousedown` on the `MenuButton` — this will open the `Menu`
2. Without releasing the mouse button yet, move your mouse over one of
the `MenuItem`s — this will highlight the currently active `MenuItem`.
3. Release the mouse button — this will invoke the currently active
`MenuItem` and close the `Menu`.

This now means that you can perform actions very quickly.

What this PR doesn't do yet is if you have a scrollable list, then it
won't scroll up or down when you reach the ends of the list. For this we
would need to introduce some new elements. The native Menu items on
macOS show a little placeholder arrow. If you put your cursor in that
area, it starts scrolling:

<img width="489" alt="image"
src="https://github.com/user-attachments/assets/e3a90d5a-daa7-4711-9e19-050578be3e02"
/>


## Test plan

1. Everything still works as expected
2. Quick release has been added:

- Listbox:
https://headlessui-react-git-feat-quick-trigger-tailwindlabs.vercel.app/listbox/listbox-with-pure-tailwind
- Menu:
https://headlessui-react-git-feat-quick-trigger-tailwindlabs.vercel.app/menu/menu
- Combobox:
https://headlessui-react-git-feat-quick-trigger-tailwindlabs.vercel.app/combobox/combobox-countries
This commit is contained in:
Robin Malfait
2025-04-24 16:01:38 +02:00
committed by GitHub
parent 730ab68345
commit 1461b65810
8 changed files with 255 additions and 33 deletions
+15
View File
@@ -18,3 +18,18 @@ Object.defineProperty(HTMLElement.prototype, 'innerText', {
this.textContent = value
},
})
// Source: https://github.com/testing-library/react-testing-library/issues/838#issuecomment-735259406
//
// Polyfill the PointerEvent class for JSDOM
class PointerEvent extends Event {
constructor(type, props) {
super(type, props)
if (props.button != null) {
// @ts-expect-error JSDOM doesn't support `button` yet...
this.button = props.button
}
}
}
// @ts-expect-error JSDOM doesn't support `PointerEvent` yet...
window.PointerEvent = PointerEvent