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

# 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.

***

## Choose the destination

| Polaris React | Polaris web components | Migration type |
| - | - | - |
| `TrapFocus` | Remove for Polaris overlays. Keep an accessible focus trap only for custom dialogs. | Remove |

***

## Map 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. |

***

## Migrate the call site

1. Find every `TrapFocus` consumer and identify which behavior, if any, still depends on it.

2. Migrate those dependent components or behaviors first.

3. Delete `TrapFocus` and its now-unused state or helper code once it has no remaining responsibility.

4. Verify the containing workflow without the removed layer.

***

## Preserve 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.

***

## Test 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.

***

## Migration example

## Migrating TrapFocus

##### Polaris web components

```tsx
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

```tsx
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>
    </>
  );
}
```

***
