Skip to content

Conversation

alii13
Copy link

@alii13 alii13 commented Oct 12, 2025

Closes chakra-ui/ark#3628

📝 Description

Fixes toast group collapsing unexpectedly when dismissing a toast while the mouse is still hovering over the group. This issue was originally reported in Ark UI (chakra-ui/ark#3628) and traced back to the Zag.js toast machine implementation.

⛳️ Current behavior (updates)

When dismissing a toast by clicking the close button while the mouse is hovering over the toast group:

  • The toasts immediately collapse even though the cursor is still within the group
  • Focus is restored to the trigger button, which causes the browser to recalculate hover state
  • The :hover pseudo-class is removed from the toast group momentarily
  • In some browsers (particularly Firefox), DOM mutations trigger spurious mouseleave/mouseenter events, causing flickering
  • This results in toasts collapsing unexpectedly, breaking the expected hover behavior
  • The user must move their cursor slightly to re-trigger the hover expansion

🚀 New behavior

With this fix:

  • Toasts remain expanded when dismissing a toast while hovering over the group
  • Focus restoration only occurs when the pointer has actually left the toast group
  • The hover state is preserved during toast dismissal operations
  • Mouse events are briefly ignored (100ms) after toast removal to prevent spurious events during DOM mutations
  • Focus is restored when the user moves their cursor away from the group
  • No flickering or unwanted collapse/expand cycles

Implementation changes:

  • Add isPointerWithin ref to track mouse position over toast group
  • Add ignoringMouseEvents ref to temporarily block mouse events after toast removal
  • Update REGION.BLUR handler to check pointer position before collapsing
  • Add guards: isPointerOut, isOverlappingAndPointerOut
  • Add actions: setPointerWithin, clearPointerWithin, clearFocusWithin, ignoreMouseEventsTemporarily
  • Only restore focus when pointer has left the group

💣 Is this a breaking change (Yes/No): No

This is a bug fix that improves the user experience without changing any APIs or breaking existing functionality. The fix is framework-agnostic and applies to all implementations (React, Vue, SolidJS, Svelte).

📝 Additional Information

Testing:
Tested in the Solid examples at http://localhost:3000/toast-overlap:

  1. ✅ Create multiple toasts
  2. ✅ Hover over toast group (toasts expand)
  3. ✅ Click X button while hovering (toasts remain expanded - fixed!)
  4. ✅ Move cursor away (toasts collapse and focus returns)
  5. ✅ Tested in both Chrome and Firefox - no flickering or collapse issues

Files modified:

  • packages/machines/toast/src/toast-group.machine.ts
  • packages/machines/toast/src/toast-group.connect.ts
  • packages/machines/toast/src/toast.types.ts

Related issue: chakra-ui/ark#3628

Before (Bug) ❌

  • Toast group collapses immediately
  • Focus restoration breaks hover state
Screen.Recording.2025-10-13.at.10.45.11.AM.mov

After (Fixed) ✅

  • Toast group stays expanded
  • Hover state preserved
Screen.Recording.2025-10-13.at.10.45.50.AM.mov

When dismissing a toast by clicking the close button while the mouse
is hovering over the toast group, the toasts would immediately collapse
even though the cursor was still within the group. This was caused by
focus restoration triggering browser hover state recalculation.

This fix adds pointer tracking to only restore focus and collapse toasts
when the pointer has actually left the toast group, maintaining the
expected hover behavior.

Changes:
- Add isPointerWithin ref to track mouse position over toast group
- Update REGION.BLUR handler to check pointer position before collapsing
- Add guards: isPointerOut, isOverlappingAndPointerOut
- Add actions: setPointerWithin, clearPointerWithin, clearFocusWithin
- Only restore focus when pointer has left the group

Fixes chakra-ui/ark#3628
Copy link

changeset-bot bot commented Oct 12, 2025

🦋 Changeset detected

Latest commit: 31874d6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 79 packages
Name Type
@zag-js/toast Patch
@zag-js/anatomy-icons Patch
@zag-js/anatomy Patch
@zag-js/core Patch
@zag-js/docs Patch
@zag-js/preact Patch
@zag-js/react Patch
@zag-js/solid Patch
@zag-js/svelte Patch
@zag-js/vue Patch
@zag-js/accordion Patch
@zag-js/angle-slider Patch
@zag-js/async-list Patch
@zag-js/avatar Patch
@zag-js/bottom-sheet Patch
@zag-js/carousel Patch
@zag-js/checkbox Patch
@zag-js/clipboard Patch
@zag-js/collapsible Patch
@zag-js/color-picker Patch
@zag-js/combobox Patch
@zag-js/date-picker Patch
@zag-js/dialog Patch
@zag-js/editable Patch
@zag-js/file-upload Patch
@zag-js/floating-panel Patch
@zag-js/hover-card Patch
@zag-js/listbox Patch
@zag-js/menu Patch
@zag-js/navigation-menu Patch
@zag-js/number-input Patch
@zag-js/pagination Patch
@zag-js/password-input Patch
@zag-js/pin-input Patch
@zag-js/popover Patch
@zag-js/presence Patch
@zag-js/progress Patch
@zag-js/qr-code Patch
@zag-js/radio-group Patch
@zag-js/rating-group Patch
@zag-js/scroll-area Patch
@zag-js/select Patch
@zag-js/signature-pad Patch
@zag-js/slider Patch
@zag-js/splitter Patch
@zag-js/steps Patch
@zag-js/switch Patch
@zag-js/tabs Patch
@zag-js/tags-input Patch
@zag-js/timer Patch
@zag-js/toggle-group Patch
@zag-js/toggle Patch
@zag-js/tooltip Patch
@zag-js/tour Patch
@zag-js/tree-view Patch
@zag-js/store Patch
@zag-js/types Patch
@zag-js/aria-hidden Patch
@zag-js/auto-resize Patch
@zag-js/collection Patch
@zag-js/color-utils Patch
@zag-js/utils Patch
@zag-js/date-utils Patch
@zag-js/dismissable Patch
@zag-js/dom-query Patch
@zag-js/file-utils Patch
@zag-js/focus-trap Patch
@zag-js/focus-visible Patch
@zag-js/highlight-word Patch
@zag-js/hotkeys Patch
@zag-js/i18n-utils Patch
@zag-js/interact-outside Patch
@zag-js/json-tree-utils Patch
@zag-js/live-region Patch
@zag-js/popper Patch
@zag-js/rect-utils Patch
@zag-js/remove-scroll Patch
@zag-js/scroll-snap Patch
@zag-js/stringify-state Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

vercel bot commented Oct 12, 2025

@alii13 is attempting to deploy a commit to the Chakra UI Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

vercel bot commented Oct 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
zag-nextjs Ready Ready Preview Oct 17, 2025 11:40pm
zag-solid Ready Ready Preview Oct 17, 2025 11:40pm
zag-svelte Ready Ready Preview Oct 17, 2025 11:40pm
zag-vue Ready Ready Preview Oct 17, 2025 11:40pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@alii13
Copy link
Author

alii13 commented Oct 13, 2025

@segunadebayo can you please take a look and review this PR?

@segunadebayo
Copy link
Member

I took a look, and it works for Chrome. I couldn't get to work in Firefox, though.

@alii13
Copy link
Author

alii13 commented Oct 17, 2025

Thank you @segunadebayo, for reviewing the PR. It was indeed not working for Firefox.
I have pushed a fix and verified it on Chrome, Safari, and Firefox; now it is working consistently across all browsers.

Can you please re-review/re-validate the PR?

Chrome

Screen.Recording.2025-10-18.at.5.01.19.AM.mov

Firefox

Screen.Recording.2025-10-18.at.5.02.37.AM.mov

@alii13
Copy link
Author

alii13 commented Oct 19, 2025

@anubra266 tagging you as well ( if you have sometime please take a look at this PR ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Toast group collapses unexpectedly in SolidJS when closing a toast

2 participants