adobe / adobe/react-spectrum

Autocomplete + Menu with createLink(MenuItem) fires two synthetic clicks on Enter key

Open
#9,431 1 comment 0 reactions 0 assignees View on GitHub
needs investigation
Dominant language
TypeScript
Stars
15.9k
Forks
1.6k
Avg merge
3d 9m
Merged PRs (30d)
59

Description

### Provide a general summary of the issue here

When using TanStack Router's createLink() to wrap MenuItem inside an Autocomplete, pressing Enter on a focused menu item triggers two synthetic click events instead of one. This causes double navigation and duplicate browser history entries.

Both click events have isTrusted: false, indicating they are both programmatically dispatched by React Aria rather than native browser events.

### 🤔 Expected Behavior?

When pressing Enter on a focused MenuItem that is wrapped with createLink() inside an Autocomplete, only one click event should be fired, resulting in a single navigation and no duplicated browser history entries.

### 😯 Current Behavior

When pressing Enter on a focused MenuItem inside AutoComplete, multiple click events are fired, resulting in duplicated browser history entries.

Two synthetic click events are fired in sequence:

1. onClick #1 - Fired on keydown (~0ms)
2. onClick #2 - Fired on keyup (~130-150ms later, immediately after onPress)

```typescript
Debug output showing the timeline:
onClick #1 {isTrusted: false, target: 'A', currentTarget: 'A', time: 3878.8}
pushState #1 {url: '/users', time: 3886.3}
onPress {pointerType: 'keyboard', time: 4029}
onClick #2 {isTrusted: false, target: 'A', currentTarget: 'A', time: 4029.5}
```

### 💁 Possible Solution

The issue appears to be a coordination problem between two keyboard handling systems:

1. Autocomplete's keyboard handler - Triggers a click on Enter keydown to select/activate the focused item
2. usePress's keyboard handler - Calls triggerSyntheticClickEvent on Enter keyup (immediately after firing onPress)

Looking at useMenuItem.ts:285-297, there's already a guard to prevent double-clicking for anchor elements:
```typescript
case 'Enter':
interaction.current = {pointerType: 'keyboard', key: 'Enter'};
// Trigger click unless this is a link. Links trigger click natively.
if ((e.target as HTMLElement).tagName !== 'A') {
(e.target as HTMLElement).click();
}
break;
```

However, onClick #1 seems to originate from Autocomplete's item selection logic rather than useMenuItem's keyboard handler.

Possible fixes:

1. Coordinate Autocomplete and usePress to prevent both from firing clicks
2. Add deduplication logic to prevent rapid successive synthetic clicks on the same element
3. Check if a navigation is already in progress before triggering another click

### 🔦 Context

I am building a command palette/menu (similar to VS Code's Cmd+K) using:

- Autocomplete for search/filtering
- Menu + MenuItem for the list items
- TanStack Router's createLink(MenuItem) for navigation

This is a production application where the double navigation causes:

- Duplicate entries in browser history
- Confusing back-button behavior for users
- Inconsistent navigation state

Current workaround: I block the second click by setting a flag in onPress and checking it in onClick:

```typescript
const blockNextClickRef = useRef(false);

const handleClick = useCallback((e: React.MouseEvent) => {
if (blockNextClickRef.current) {
e.preventDefault();
e.stopPropagation();
blockNextClickRef.current = false;
return;
}
}, []);

const handlePress = useCallback((e: PressEvent) => {
if (e.pointerType === 'keyboard') {
blockNextClickRef.current = true;
}
}, []);

Item

```

### 🖥️ Steps to Reproduce

I was not able to reproduce the issue outside of my codebase, however I did my best to provide a similar context as my codebase (let me know how I can help): https://stackblitz.com/edit/tanstack-router-m5tec7wq?file=src%2Froutes%2F__root.tsx

### Version

1.14.0

### What browsers are you seeing the problem on?

Microsoft Edge

### If other, please specify.

All browsers

### What operating system are you using?

macOS

### 🧢 Your Company/Team

_No response_

### 🕷 Tracking Issue

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.