Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/components/sonner/Toaster.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,24 @@ onBeforeUnmount(() => {

<template>
<Teleport to="body">
<!--
The column is teleported outside every overlay, so to an open Dialog,
Sheet or Popover a press on a toast is an "outside" interaction: Reka's
DismissableLayer listens for pointerdown / focusin on the document and
dismisses the layer — closing the user's dialog (and its unsaved input)
just because they closed a notification. Reka's own Toast avoids this by
registering its viewport as a DismissableLayerBranch, which reka-ui does
not export; stopping these two events here, before they reach the
document, is the public equivalent. Handlers on the toast itself still
run — only the document-level listeners stop seeing toast interactions.
-->
<ol
:class="cn('memoh-toaster', `memoh-toaster--${props.position}`, props.class)"
role="region"
aria-label="Notifications"
tabindex="-1"
@pointerdown.stop
@focusin.stop

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the modal focus trap when filtering focusin

When a modal Dialog or Sheet is open and a user clicks a toast button, this modifier also hides the focusin event from Reka's trapped FocusScope, not only from DismissableLayer. Reka's maintainer confirms that the dialog scope normally prevents teleported outside elements from taking focus (source); after this change the toast button can instead become document.activeElement outside the modal—and inside the toaster subtree that the modal marks aria-hidden. A non-dismissing text action can leave focus there, while removing the focused toast can drop focus to the body, breaking the modal focus-containment contract. Suppress the dismissal specifically or retain/restore focus inside the modal rather than stopping focusin propagation globally.

Useful? React with 👍 / 👎.

>
<TransitionGroup name="memoh-toast">
<!--
Expand Down
Loading