Description
Provide a general summary of the issue here
If DOM manipulation occurs during the onPress handler in the useButton hook, click events fail to fire, even when event listeners are set to the capture phase.
Screen.Recording.2024-05-27.at.4.24.24.pm.mov
Event listener used
window.addEventListener("click", () => console.log("clicked"), true);
🤔 Expected Behavior?
Click events should fire reliably when a button is clicked, even if DOM manipulation occurs during the onPress handler. Event listeners, especially those set in the capture phase, should detect these events without issue.
😯 Current Behavior
When DOM manipulation occurs within the onPress handler in the useButton hook, click events fail to fire. This issue persists even when event listeners are set to the capture phase. Here is a link to the code sandbox
We first recognised this issue in Google Tag Manager (GTM), where we observed that events on buttons removed from the DOM by the onPress handler were not being picked up. This led to inconsistencies in our event tracking and analytics
Error: No specific error message, but click events are not registered by Google Tag Manager (GTM) or Console Logs. The event loop isn't complete and therefore all listeners don't detect click. This appears to only be an issue with "click" events.
💁 Possible Solution
The problem can be mitigated by deferring the execution of the onPress handler. This can be done using setTimeout with a delay of 0 or using Promise.resolve().then(). This ensures that the event loop processes before DOM manipulation interferes with event handling.
Code Example:
onPress: (e) => {
e.continuePropagation();
setTimeout(() => {
if (onPress) {
onPress(e);
}
}, 0);
}
However, this is a hack. I believe this should be fixed within Adobe Spectrum.
🔦 Context
This issue impacts the reliability of event tracking using GTM on our buttons. When a button triggers a DOM manipulation that removes it, the associated click event is not captured, leading to inconsistencies in our analytics and tracking.
Screen.Recording.2024-05-27.at.4.24.24.pm.mov
🖥️ Steps to Reproduce
Code Sandbox Link
- Create a button using the useButton hook with an onPress handler that manipulates the DOM (e.g., removing the button).
- Add a click event listener in the capture phase to the window.
- Click the button and observe that the click event is not fired.
const ButtonTest = (args) => {
const [hasButton, setHasButton] = React.useState(true);
window.addEventListener('click', () => console.log('clicked'), true);
const removeButton = () => {
setHasButton((prev) => !prev);
};
return (
hasButton && (
<Button {...args} onPress={removeButton}>
{args.children}
</Button>
)
);
};
For this Sandbox, open the console and see that the button with no DOM manipulation has a console.log fired, but the one with doesn't.
Version
"react-aria": "^3.28.0",
What browsers are you seeing the problem on?
Chrome, Safari, Microsoft Edge
If other, please specify.
No response
What operating system are you using?
MacOS
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response