---
title: Migrate Navigation from Polaris React
description: >-
  Replace the Polaris React Navigation component with a concise, single-level
  s-app-nav.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/navigation
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/navigation.md
api_name: app-home
---

# Migrate Navigation from Polaris React

Replace Polaris React `Navigation` with [`s-app-nav`](https://shopify.dev/docs/api/app-home/app-bridge-web-components/app-nav). App navigation renders in the Shopify admin rather than inside the app's `Frame`.

`s-app-nav` supports one level of `s-link` children. Flatten sections and nested items intentionally instead of reproducing the old navigation hierarchy.

***

## Migrate primary navigation

## Migrating primary app navigation

##### Polaris web components

```tsx
function AppNavigation() {
  return (
    <s-app-nav>
      <s-link href="/products">Products</s-link>
      <s-link href="/settings">Settings</s-link>
    </s-app-nav>
  );
}
```

##### Polaris React

```tsx
import {Navigation} from '@shopify/polaris';

export function AppNavigation() {
  return (
    <Navigation location="/products">
      <Navigation.Section
        items={[
          {label: 'Home', url: '/'},
          {label: 'Products', url: '/products'},
          {label: 'Settings', url: '/settings'},
        ]}
      />
    </Navigation>
  );
}
```

`s-app-nav` renders only in the Shopify admin shell, so this admin navigation example isn't available as an isolated live preview.

Keep `s-app-nav` mounted near the app root rather than rendering a different navigation component for each route.

***

## Map navigation items

| Polaris React | Polaris web components | Migration notes |
| - | - | - |
| `Navigation.Section` | Remove | `s-app-nav` doesn't display section containers or headings. |
| `items` | `s-link` children | Render each primary destination as a link. |
| Item `label` | Link text | Use a concise noun that matches the destination page title. |
| Item `url` | `href` | Preserve a real URL for direct and modified navigation. |
| `location` and item `selected` | Remove | The host derives the active destination from the current URL. |
| Item `onClick` | Link navigation or a page-level action | Keep navigation declarative. Move non-navigation actions out of app nav. |
| Item `icon`, `badge`, `exactMatch`, or `matchPaths` | Remove | The destination doesn't expose these presentation and matching controls. |

***

## Flatten nested navigation

`s-app-nav` doesn't support nested items. For each `subNavigationItems` tree, choose one of these migrations:

* Promote frequently used destinations to top-level app-nav links.
* Keep one top-level link and move child destinations into the landing page.
* Use page-level tabs or links when the destinations are alternate views of one resource.
* Remove destinations that duplicate breadcrumbs, page actions, or contextual resource links.

Don't encode hierarchy into labels such as `Products > Collections`. Use concise labels and make the destination page establish its own context.

***

## Preserve router behavior

Use `href` values that the embedded app router can resolve directly. Verify direct loads, browser back and forward navigation, copied URLs, and modified clicks. Don't replace links with click handlers that call the router unless the control isn't navigation.

If the app mounts below a path such as `/app`, then include that base path consistently in every destination. The App nav reference documents `rel="home"` specifically for links inside `s-app-nav`:

```html
<s-app-nav>
  <s-link href="/app" rel="home">Home</s-link>
  <s-link href="/app/products">Products</s-link>
  <s-link href="/app/settings">Settings</s-link>
</s-app-nav>
```

The `rel="home"` link sets the non-root home route for the app name in Shopify admin; it doesn't render a visible **Home** navigation item. Generic `s-link` JSX types don't expose `rel`, so keep this App nav-specific pattern in markup rather than reusing it on links elsewhere.

***

## Remove the Frame dependency

Polaris React passed `Navigation` to the `navigation` prop on `Frame`. Render `s-app-nav` near the app root, and remove Frame state used only to open or dismiss mobile navigation. The Shopify admin owns the surrounding responsive shell.

***

## Test the migration

* Visit every destination through app nav and by loading its URL directly.
* Verify the active destination follows route changes and browser history.
* Test modified clicks, opening links in a new tab, and copied URLs.
* Confirm that nested destinations remain discoverable after flattening.
* Resize the app, and confirm that app nav doesn't duplicate an in-iframe navigation shell.

***

## Remove Polaris React

After every `Navigation` call site is migrated, remove `Navigation`, its `Frame` prop, mobile-navigation state, and imported navigation icons used only by it. Remove `@shopify/polaris` only after no other route in scope imports it.

***

## Related guidance

* [App nav](https://shopify.dev/docs/api/app-home/app-bridge-web-components/app-nav)
* [Migrate Frame from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/frame)
* [Migrate Page from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/page)

***
