---
title: Migrate Portal from Polaris React
description: Learn how to migrate Polaris React Portal to Polaris web components.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/portal
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/portal.md
api_name: app-home
---

# Migrate Portal from Polaris React

Keep a framework portal only for custom UI that genuinely must escape its container. Polaris web component overlays manage their own rendering and don't need a Polaris portal.

***

## Choose the destination

| Polaris React | Polaris web components | Migration type |
| - | - | - |
| `Portal` | Keep the framework portal only for custom UI. Polaris overlays don't require it. | Native DOM |

***

## Map portal responsibilities

| Polaris React usage | Polaris web components | Migration notes |
| - | - | - |
| Modal content | `s-modal` | Render normally and connect its trigger with `commandFor`. |
| Popover content | `s-popover` | Let the component manage placement, stacking, and dismissal. |
| Arbitrary content moved to `document.body` | Render in document flow or review the custom overlay separately | Preserve focus order, clipping, and cleanup. |

***

## Migrate the call site

1. Locate why `Portal` is used and the exact element or event target it controls.

2. Implement the native DOM behavior in the framework lifecycle that owns that target.

3. Add cleanup and protect against targets that aren't mounted.

4. After verification, remove the `Portal` import and any Polaris-only state, wrappers, or helpers that no longer have a caller.

***

## Preserve these behaviors

* The original trigger and target of the behavior.
* Framework mount, update, and cleanup timing.
* Focus and keyboard behavior where relevant, without unexpected global side effects.

***

## Test and remove Polaris React

Test the migrated `Portal` behavior through its user-visible outcome. Verify timing, focus or keyboard behavior, repeated mounts, missing targets, and cleanup on unmount.

Don't remove `@shopify/polaris` while another component still imports it. Once all call sites are migrated, remove the package and its provider-level setup, then run the app's full test suite.

***
