Open Menu and Listbox on mousedown (#3689)
This is a small behavioral change, but this PR will change when the `Menu` and `Listbox` components open. This PR will now open the `Menu` and `Listbox` components on `mousedown` instead of `click`. This will make it feel more responsive and faster to the user. This is also how macOS for example opens menu-like components on the OS level. This is also how the native `<select>` (at least on macOS) works.
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Improve `Menu` component performance ([#3685](https://github.com/tailwindlabs/headlessui/pull/3685))
|
||||
- Improve `Listbox` component performance ([#3688](https://github.com/tailwindlabs/headlessui/pull/3688))
|
||||
- Open `Menu` and `Listbox` on `mousedown` ([#3689](https://github.com/tailwindlabs/headlessui/pull/3689))
|
||||
|
||||
## [2.2.1] - 2025-04-04
|
||||
|
||||
|
||||
@@ -3963,11 +3963,10 @@ describe('Mouse interactions', () => {
|
||||
it(
|
||||
'should be possible to click outside of the listbox, on an element which is within a focusable element, which closes the listbox',
|
||||
suppressConsoleLogs(async () => {
|
||||
let focusFn = jest.fn()
|
||||
render(
|
||||
<div>
|
||||
<Listbox value={undefined} onChange={(x) => console.log(x)}>
|
||||
<Listbox.Button onFocus={focusFn}>Trigger</Listbox.Button>
|
||||
<Listbox.Button>Trigger</Listbox.Button>
|
||||
<Listbox.Options>
|
||||
<Listbox.Option value="alice">alice</Listbox.Option>
|
||||
<Listbox.Option value="bob">bob</Listbox.Option>
|
||||
@@ -3995,9 +3994,6 @@ describe('Mouse interactions', () => {
|
||||
|
||||
// Ensure the outside button is focused
|
||||
assertActiveElement(document.getElementById('btn'))
|
||||
|
||||
// Ensure that the focus button only got focus once (first click)
|
||||
expect(focusFn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -393,7 +393,8 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
|
||||
}
|
||||
})
|
||||
|
||||
let handleClick = useEvent((event: ReactMouseEvent) => {
|
||||
let handleMouseDown = useEvent((event: ReactMouseEvent) => {
|
||||
if (event.button !== 0) return // Only handle left clicks
|
||||
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
|
||||
if (machine.state.listboxState === ListboxStates.Open) {
|
||||
flushSync(() => machine.actions.closeListbox())
|
||||
@@ -450,7 +451,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
|
||||
onKeyDown: handleKeyDown,
|
||||
onKeyUp: handleKeyUp,
|
||||
onKeyPress: handleKeyPress,
|
||||
onClick: handleClick,
|
||||
onMouseDown: handleMouseDown,
|
||||
},
|
||||
focusProps,
|
||||
hoverProps,
|
||||
|
||||
@@ -3077,11 +3077,10 @@ describe('Mouse interactions', () => {
|
||||
it(
|
||||
'should be possible to click outside of the menu, on an element which is within a focusable element, which closes the menu',
|
||||
suppressConsoleLogs(async () => {
|
||||
let focusFn = jest.fn()
|
||||
render(
|
||||
<div>
|
||||
<Menu>
|
||||
<Menu.Button onFocus={focusFn}>Trigger</Menu.Button>
|
||||
<Menu.Button>Trigger</Menu.Button>
|
||||
<Menu.Items>
|
||||
<Menu.Item as="a">alice</Menu.Item>
|
||||
<Menu.Item as="a">bob</Menu.Item>
|
||||
@@ -3109,9 +3108,6 @@ describe('Mouse interactions', () => {
|
||||
|
||||
// Ensure the outside button is focused
|
||||
assertActiveElement(document.getElementById('btn'))
|
||||
|
||||
// Ensure that the focus button only got focus once (first click)
|
||||
expect(focusFn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -229,7 +229,8 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
|
||||
state.itemsElement,
|
||||
])
|
||||
|
||||
let handleClick = useEvent((event: ReactMouseEvent) => {
|
||||
let handleMouseDown = useEvent((event: ReactMouseEvent) => {
|
||||
if (event.button !== 0) return // Only handle left clicks
|
||||
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
|
||||
if (disabled) return
|
||||
if (menuState === MenuState.Open) {
|
||||
@@ -273,7 +274,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
|
||||
autoFocus,
|
||||
onKeyDown: handleKeyDown,
|
||||
onKeyUp: handleKeyUp,
|
||||
onClick: handleClick,
|
||||
onMouseDown: handleMouseDown,
|
||||
},
|
||||
focusProps,
|
||||
hoverProps,
|
||||
|
||||
Reference in New Issue
Block a user