Summary
Opening and closing an s-app-window once causes every s-modal opened afterwards to render with the wrong overlay.
We found no in-app way to recover. A full document reload of the embedded frame is the only thing that restores the expected behaviour.
Environment
-
https://cdn.shopify.com/shopifycloud/app-bridge.js -
https://cdn.shopify.com/shopifycloud/polaris.js -
Both loaded from the Shopify CDN and fetched on 2026-08-14
-
Polaris build stamp:
-26021 -
Embedded app running inside Shopify Admin
-
Chrome on macOS
-
Vue 3 app, although this does not appear to be framework-specific
-
Both
s-modalands-app-windoware plain custom elements using their own APIs (showOverlay(),show(),hide())
Steps to reproduce
-
On an embedded app page, open an
s-modal.-
The entire Shopify Admin dims, including the sidebar and top bar.
-
The modal is centred in the viewport.
-
This is the correct behaviour.
-
-
Close the modal.
-
Open an
s-app-window, then close it.-
Calling
hide()reproduces the issue. -
Clicking the
✕in the window’s own top bar also reproduces the issue.
-
-
Open the same
s-modalagain.
Expected
The modal should render exactly as it did in step 1:
-
The entire Shopify Admin should be dimmed.
-
The sidebar and top bar should be covered by the overlay.
-
The modal should be centred in the viewport.
Actual
The Admin no longer renders its overlay.
There are two visible consequences:
-
The dim is confined to the app’s iframe. The Shopify Admin sidebar and top bar remain bright, making the modal look like an overlay inside a panel rather than an overlay across the Admin.
-
The modal is approximately 120px left of centre.
The second issue appears to be caused by Polaris’ sidebar compensation:
.embedded.size-base {
transform: translate(
calc(-50% - var(--s-sidebar-offset-26021))
);
}
--s-sidebar-offset-26021 is 120px.
The measured transform is:
matrix(1, 0, 0, 1, -430, 0)
This decomposes exactly as:
-310px - 120px = -430px
where -310px is half of the 620px size-base modal width, and -120px is the sidebar compensation.
That compensation only produces a visually centred modal when the Admin’s full-viewport overlay is present. Without the host overlay, the modal is effectively shifted 120px to the left.
The broken state persists
Once the page enters this state, every subsequent modal on that page is affected.
A full reload of the embedded frame is the only recovery mechanism we have found.
What we ruled out
We instrumented the app side extensively.
Every value observable from inside the app frame is identical before and after the s-app-window cycle.
Measured on the s-modal’s shadow <dialog> |
Before | After |
|---|---|---|
className |
modal embedded size-base align-self-center has-backdrop |
Identical |
getComputedStyle(dialog, '::backdrop').backgroundColor |
rgba(0, 0, 0, 0.5) |
Identical |
insetInlineStart |
783px |
Identical |
transform |
matrix(1, 0, 0, 1, -430, 0) |
Identical |
--s-sidebar-offset-26021 |
120px |
Identical |
dialog.matches(':modal') |
true |
Identical |
App frame innerWidth, modal closed → open |
1566 → 1566 |
Identical |
In particular:
-
The modal retains its
has-backdropclass. -
Its
::backdropremainsrgba(0, 0, 0, 0.5). -
The in-iframe backdrop itself is unchanged.
What disappears is the overlay that Shopify Admin renders in its own document. That is the only layer capable of covering the Admin sidebar and top bar.
Additional checks
1. The RPC still fires and succeeds
We wrapped:
window.shopify._internal.modal.show
window.shopify._internal.modal.hide
After the s-app-window cycle:
-
The app still calls
showwith the same modal ID. -
The RPC still resolves successfully.
-
There are no errors.
-
The behaviour is the same from the app’s perspective as before the cycle.
So the app is still asking the host to show the overlay; the host simply does not render it.
2. App Bridge clears its s-app-window state
After closing the window:
-
Internal open-state flags are cleared.
-
The element can be reopened normally.
This does not appear to be a stuck s-app-window state on our side.
3. The window iframe is torn down
window.parent.frames.length is unchanged before and after the cycle.
4. The app frame is never resized
window.innerWidth remains 1566 regardless of whether the modal is open or closed, both before and after the s-app-window cycle.
This suggests the Admin overlay is a separate host-level layer rather than something implemented by resizing the app iframe.
Conclusion
Since:
-
Nothing observable inside the app document changes.
-
The modal remains in the correct state.
-
The modal’s
::backdropremains unchanged. -
The modal RPC continues to fire and succeed.
-
The app frame is not resized.
-
The issue begins only after an
s-app-windowhas been opened and closed.
This appears to indicate that Shopify Admin stops rendering its host-level modal overlay after an s-app-window has been used during that page session.
Impact
Any embedded app that uses both s-app-window and s-modal can end up with permanently degraded modals after a merchant opens the window once.
There is currently no in-app workaround we have found.
The only known recovery is a full reload of the embedded frame, which is not something we can safely force because it would discard the app’s current state.
Question
Is there a supported way to make Shopify Admin re-establish the modal overlay after an s-app-window closes, without requiring a full document reload?
Screenshots
-
Correct: Fresh page load → open
s-modal- Entire Admin is dimmed.
- Modal is centred in the viewport.
-
Broken: Same page → open/close
s-app-window→ opens-modal

