diff --git a/.changeset/app-provider-custom-link-component.md b/.changeset/app-provider-custom-link-component.md
new file mode 100644
index 0000000000..57053381b3
--- /dev/null
+++ b/.changeset/app-provider-custom-link-component.md
@@ -0,0 +1,14 @@
+---
+'@shopify/shopify-app-remix': minor
+---
+
+`AppProvider` now accepts an optional `linkComponent` prop, allowing apps to override the default `RemixPolarisLink`. This unblocks use cases like passing Remix's `NavLink` to drive active-route styling for Polaris `Navigation.Item` or `Link`. When omitted, the existing `RemixPolarisLink` is used, so this is a non-breaking addition.
+
+```tsx
+import {NavLink} from '@remix-run/react';
+import {AppProvider} from '@shopify/shopify-app-remix/react';
+
+
+
+
+```
diff --git a/packages/apps/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx b/packages/apps/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx
index 8cc90ff4f5..f44cf7d76e 100644
--- a/packages/apps/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx
+++ b/packages/apps/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx
@@ -39,6 +39,26 @@ export interface AppProviderProps extends Omit<
* {@link https://polaris.shopify.com/components/utilities/app-provider}
*/
i18n?: PolarisAppProviderProps['i18n'];
+ /**
+ * A custom link component to use throughout the app. Polaris components that
+ * render links (such as `Link`, `Navigation.Item`, etc.) will forward all
+ * link props to this component.
+ *
+ * Defaults to a thin wrapper around Remix's `Link` that strips Polaris-only
+ * props. Override when you need access to Remix navigation state, for
+ * example to drive an active style with `NavLink`:
+ *
+ * ```tsx
+ * import {NavLink} from '@remix-run/react';
+ *
+ *
+ *
+ *
+ * ```
+ *
+ * {@link https://polaris.shopify.com/components/utilities/app-provider#props}
+ */
+ linkComponent?: PolarisAppProviderProps['linkComponent'];
/**
* Used internally by Shopify. You don't need to set this.
* @private
@@ -115,6 +135,7 @@ export function AppProvider(props: AppProviderProps) {
apiKey,
i18n,
isEmbeddedApp = true,
+ linkComponent = RemixPolarisLink,
__APP_BRIDGE_URL = APP_BRIDGE_URL,
...polarisProps
} = props;
@@ -141,7 +162,7 @@ export function AppProvider(props: AppProviderProps) {
{isEmbeddedApp && }
{children}
diff --git a/packages/apps/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx b/packages/apps/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx
index a0c21d8c31..023f362a87 100644
--- a/packages/apps/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx
+++ b/packages/apps/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx
@@ -72,6 +72,24 @@ describe('', () => {
});
});
+ it('forwards a custom linkComponent to the Polaris provider', () => {
+ // GIVEN a consumer-supplied link component (e.g. Remix `NavLink`)
+ const CustomLink = (props: any) => ;
+
+ // WHEN
+ const component = mount(
+
+ Hello world
+ ,
+ );
+
+ // THEN the Polaris provider receives the custom component, not the
+ // default RemixPolarisLink.
+ expect(component).toContainReactComponent(PolarisAppProvider, {
+ linkComponent: CustomLink,
+ });
+ });
+
it('handles "shopify:navigate" events correctly', () => {
const component = mount(