Migrate Frame from Polaris React
Polaris React Frame has no replacement wrapper. In an embedded app, the Shopify admin and App Bridge provide the surrounding chrome. Migrate each responsibility that depends on Frame, and then render the app routes without it.
Don't replace Frame with a generic div, s-box, or compatibility component. Those wrappers don't reproduce its navigation, overlays, loading, or save-bar behavior.
Anchor to Migrate the app shellMigrate the app shell
The following example moves primary navigation to s-app-nav, moves the page title and content to Polaris web components, and removes the in-iframe shell.
Migrating the embedded app shell
Polaris web components
function AppShell() {
return (
<>
<s-app-nav>
<s-link href="/products">Products</s-link>
<s-link href="/settings">Settings</s-link>
</s-app-nav>
<s-page heading="Products">
<s-section>
<s-paragraph>Manage products from this page.</s-paragraph>
</s-section>
</s-page>
</>
);
}Polaris React
import {Card, Frame, Navigation, Page, Text} from '@shopify/polaris';
export function AppShell() {
const navigation = (
<Navigation location="/products">
<Navigation.Section
items={[
{label: 'Home', url: '/'},
{label: 'Products', url: '/products'},
{label: 'Settings', url: '/settings'},
]}
/>
</Navigation>
);
return (
<Frame navigation={navigation}>
<Page title="Products">
<Card>
<Text as="p">Manage products from this page.</Text>
</Card>
</Page>
</Frame>
);
}s-app-nav renders only in the Shopify admin shell, so this admin navigation example isn't available as an isolated live preview.
In a real app, keep s-app-nav mounted near the app root and render the active route below it. Each route can own its s-page heading, actions, and sections.
Anchor to Migrate Frame responsibilitiesMigrate Frame responsibilities
Remove Frame only after every responsibility used by the app has a destination:
| Frame responsibility | Polaris web components | Migration guidance |
|---|---|---|
navigation | s-app-nav | Render real s-link destinations and keep them synchronized with the app router. |
topBar | The Shopify admin plus s-page | Move page context and actions to each route. Don't recreate an in-iframe top bar. |
contextualSaveBar | data-save-bar or the Save Bar API | Migrate dirty state, save, discard, and navigation protection together. |
Toast descendants | Toast API | Replace rendered toast state with shopify.toast.show(). |
Loading descendants | Loading API | Connect route-level loading state to shopify.loading(). |
| Modal and popover portals | s-modal, s-popover, or s-menu | Use documented overlay components so that they manage focus and dismissal. |
children | App routes and page components | Render the existing route tree directly. |
Follow the linked component migration guide for each responsibility before removing the wrapper.
Frame and Navigation often introduce state that opens or dismisses mobile navigation. Remove state and callbacks used only for that in-iframe shell. The Shopify admin owns the surrounding responsive navigation behavior.
Keep route state in the app router. Use real href values so that modified clicks, copied links, direct navigation, and browser history continue to work.
Anchor to Remove provider and style dependencies separatelyRemove provider and style dependencies separately
Removing Frame doesn't mean every Polaris React dependency is gone. Keep AppProvider while a mounted route still renders components from @shopify/polaris. Remove Polaris styles and provider setup only after their final consumer is migrated.
Delete CSS that targets .Polaris-Frame, .Polaris-Navigation, or other Frame internals. Don't copy those internal selectors or layout variables into the new shell.
Anchor to Test the migrationTest the migration
- Open every primary navigation destination directly and through
s-app-nav. - Test browser back and forward navigation, modified clicks, and copied URLs.
- Verify route-level loading, toasts, save bars, modals, and popovers without
Frame. - Test keyboard focus after route changes and overlay dismissal.
- Resize the embedded app, and confirm that no in-iframe shell duplicates the surrounding Shopify admin.
- Run the app's production build and check the console for missing context or custom-element errors.
Anchor to Remove Polaris ReactRemove Polaris React
After all Frame responsibilities are migrated, remove the Frame import, wrapper, shell-only state, and internal CSS. Remove @shopify/polaris only after no other route in scope imports it.
- App nav
- Migrate Navigation from Polaris React
- Migrate ContextualSaveBar from Polaris React
- Migrate Toast from Polaris React
- Migrate Loading from Polaris React
- Remove AppProvider after migrating Polaris React