adobe / adobe/spectrum-web-components
[Bug]: interaction="manual" overlay — sp-opened never dispatches when interaction="modal" overlay is active, causing app freeze
- Dominant language
- TypeScript
- Stars
- 1.5k
- Forks
- 262
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 68
Description
### Code of conduct
- [x] I agree to follow this project's code of conduct.
### Impacted component(s)
@spectrum-web-components/overlay
### Library version
@spectrum-web-components/overlay: 1.9.0
### Expected behavior
`sp-opened `fires on bgTrigger within ~50ms, consistent with normal manual overlay behaviour.
### Actual behavior
When an interaction="modal" overlay is open, calling Overlay.open(trigger, "manual", content, opts) on a background element causes sp-opened to never dispatch on the trigger. The overlay gets permanently stuck in state="opening".
In applications that await sp-opened to resolve an open-state promise, this causes a complete and unrecoverable app freeze — Lit's update cycle hangs indefinitely and the page must be reloaded.
`sp-opened` never fires. The overlay is permanently stuck in state="opening". No error is surfaced to the caller.
### Screenshots
_No response_
### What browsers are you seeing the problem in?
Chrome
### How can we reproduce this issue?
1. Open an `interaction="modal"` overlay (e.g. via Overlay.open(trigger, "modal", content, opts)) and wait for sp-opened to fire on its trigger.
2. While that modal overlay is still open, call Overlay.open(bgTrigger, "manual", content, opts) on a background element
3. Listen for sp-opened on bgTrigger
### Sample code or abstract reproduction which illustrates the problem
showModal() — called internally by SWC when opening a type="modal" overlay — makes all background elements natively inert per the HTML spec. When SWC subsequently tries to open the manual overlay, it calls showPopover() on an element that is now in the inert subtree. The browser throws NotSupportedError. This throw is unhandled and aborts the open sequence before makeTransition() runs, so sp-opened is never dispatched.
Overlay.open(trigger, "manual", ...)
→ managePopoverOpen()
→ ensureOnDOM()
→ shouldShowPopover()
→ this.dialogEl.showPopover() // ← throws NotSupportedError, no try/catch
→ ensureOnDOM() aborts
→ makeTransition() never called
→ sp-opened never dispatched
We believe the fix belongs in `OverlayPopover.shouldShowPopover() `— wrapping showPopover() with a try/catch and setting this.open = false on NotSupportedError so sp-closed fires and callers can recover gracefully:
```
try {
this.dialogEl.showPopover();
this.managePosition();
} catch (err) {
if (err instanceof DOMException && err.name === 'NotSupportedError') {
this.open = false; // triggers sp-closed so callers can recover
return;
}
throw err;
}
```
### Severity
None
### Logs taken while reproducing problem
_No response_
### Would you like to track this issue in Jira?
- [ ] Yes, please tell me the ticket number!
Contributor guide
Research direction
Start in OverlayPopover.shouldShowPopover() and trace the Overlay.open() path through managePopoverOpen() and ensureOnDOM(). Reproduce the modal-overlay then background manual-overlay sequence in Chrome, and verify that a NotSupportedError no longer leaves the overlay in state="opening" and that recovery events are dispatched as described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100