Migrate Trap Focus from Polaris React
Remove TrapFocus around migrated Polaris overlays because the destination manages focus. Keep a custom trap only as part of a complete accessible custom dialog.
Anchor to Choose the destinationChoose the destination
| Polaris React | Polaris web components | Migration type |
|---|---|---|
TrapFocus | Remove for Polaris overlays. Keep an accessible focus trap only for custom dialogs. | Remove |
Anchor to Map focus-trap responsibilitiesMap focus-trap responsibilities
| Polaris React | Polaris web components | Migration notes |
|---|---|---|
trapping around a modal | s-modal | Remove the wrapper and verify focus enters, remains within, and returns to the trigger. |
trapping around a popover | s-popover | Use the destination interaction model instead of forcing modal behavior. |
| Custom dialog content | Complete accessible custom dialog implementation | Keep a trap only when you also own labelling, dismissal, inert background behavior, and focus restoration. |
Anchor to Migrate the call siteMigrate the call site
-
Find every
TrapFocusconsumer and identify which behavior, if any, still depends on it. -
Migrate those dependent components or behaviors first.
-
Delete
TrapFocusand its now-unused state or helper code once it has no remaining responsibility. -
Verify the containing workflow without the removed layer.
Anchor to Preserve these behaviorsPreserve these behaviors
- Any user-visible behavior that was coupled to the removed component.
- Behavior of remaining descendants, including focus, scrolling, overlays, or context where relevant.
- Test setup and cleanup paths that referenced the removed layer.
Anchor to Test and remove Polaris ReactTest and remove Polaris React
Test the workflows that formerly depended on TrapFocus. Verify remaining descendants render correctly and that focus, scrolling, overlays, and test setup no longer rely on the removed layer.
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.
Anchor to Migration exampleMigration example
Migrating TrapFocus
Polaris web components
export function TrapFocusMigrationExample() {
return (
<>
<s-button commandFor="focus-modal" command="--show">
Open dialog
</s-button>
<s-modal id="focus-modal" heading="Confirm changes">
<s-paragraph>Review the changes before continuing.</s-paragraph>
<s-button
slot="primary-action"
variant="primary"
commandFor="focus-modal"
command="--hide"
>
Continue
</s-button>
</s-modal>
</>
);
}Polaris React
import {Button, Modal, TrapFocus} from '@shopify/polaris';
import {useState} from 'react';
export function TrapFocusMigrationExample() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open dialog</Button>
<Modal open={open} onClose={() => setOpen(false)} title="Confirm changes">
<TrapFocus trapping>
<Button onClick={() => setOpen(false)}>Continue</Button>
</TrapFocus>
</Modal>
</>
);
}