Migrate Popover from Polaris React
Replace Polaris React Popover with s-popover for contextual content anchored to a trigger. Use s-menu when the overlay contains only actions, and use s-modal when the task requires more space or focused attention.
Anchor to Migrate contextual contentMigrate contextual content
Polaris React passes an activator into Popover and controls active state. Polaris web components render a trigger and popover as siblings. The trigger references the popover's ID with commandFor, so you can remove state used only to open and close the overlay.
Migrating inventory details
Polaris web components
function InventoryDetails() {
return (
<>
<s-button commandFor="inventory-popover">View inventory</s-button>
<s-popover id="inventory-popover" inlineSize="320px">
<s-box padding="base">
<s-stack gap="small">
<s-heading>Inventory</s-heading>
<s-text>Ottawa: 12 available</s-text>
<s-text>Toronto: 8 available</s-text>
</s-stack>
</s-box>
</s-popover>
</>
);
}Polaris React
import {Button, Popover, Text} from '@shopify/polaris';
import {useState} from 'react';
export function InventoryDetails() {
const [active, setActive] = useState(false);
return (
<Popover
active={active}
activator={
<Button onClick={() => setActive((open) => !open)}>
View inventory
</Button>
}
onClose={() => setActive(false)}
sectioned
>
<Text as="h2" variant="headingSm">Inventory</Text>
<Text as="p">Ottawa: 12 available</Text>
<Text as="p">Toronto: 8 available</Text>
</Popover>
);
}Preview
Anchor to Updated propertiesUpdated properties
| Polaris React | Polaris web components | Migration notes |
|---|---|---|
activator | A sibling s-button with commandFor | Give the popover a stable, unique ID. Omit command to toggle, or use command="--show" when the trigger should only open it. |
active | Remove | The trigger and popover manage visibility through commands. |
onClose | The hide event; use command="--hide" on an explicit close or apply action | Keep a callback only when app state must react to every close path. |
sectioned | s-box padding="base" or s-section | Compose the content and spacing explicitly. |
fullWidth or fluidContent | No direct equivalent | Set inlineSize only when the content needs an explicit width. |
preferredAlignment and preferredPosition | Remove | The popover positions itself from its trigger. |
Popover.Pane and Popover.Section | s-box, s-section, or s-stack | Preserve content hierarchy and scrolling requirements through composition. |
s-popover can't open automatically on page load. A user interaction must open it. If content must be visible immediately, then place it in the page or use a different pattern.
The command value is optional. Omit it when the trigger should toggle the popover. Use explicit --show or --hide when a control has only one valid outcome.
Anchor to Choose the right overlayChoose the right overlay
- Use
s-popoverfor contextual information, settings, or a compact form related to one trigger. - Use
s-menufor a compact list of actions. Menu children are buttons, not Polaris React action descriptor objects. - Use
s-modalfor confirmation, complex forms, or tasks that need focused attention. - Keep persistent actions and important instructions visible in the page.
Don't move essential instructions into a popover only to reduce page content. Users shouldn't need to discover hidden content to complete the task.
Anchor to Preserve app state intentionallyPreserve app state intentionally
Remove active state when it exists only to control the overlay. Keep state for values inside the popover, applied filters, pending operations, or results.
When applying a form or filter, update app state first and then hide the popover. Keep validation errors visible and leave the popover open when the operation fails.
Anchor to Test the migrationTest the migration
- Open and close the popover with a pointer and keyboard.
- Verify the trigger keeps focus when the popover opens, and remains usable after it closes.
- Test the Escape key, outside interaction, and any explicit hide control that the app adds;
s-popoverdoesn't add a dismiss control. - Confirm that content remains usable at narrow app widths and with long translated text.
- Verify nested interactive content doesn't close before its action completes.
Anchor to Remove Polaris ReactRemove Polaris React
After every Popover call site is migrated, remove the Popover import and state or callbacks used only to control it. Remove @shopify/polaris only after no other route in scope imports it.