Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/app-provider-custom-link-component.md
Original file line number Diff line number Diff line change
@@ -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';

<AppProvider apiKey={apiKey} linkComponent={NavLink}>
<Outlet />
</AppProvider>
```
Original file line number Diff line number Diff line change
Expand Up @@ -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';
*
* <AppProvider apiKey={apiKey} linkComponent={NavLink}>
* <Outlet />
* </AppProvider>
* ```
*
* {@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
Expand Down Expand Up @@ -115,6 +135,7 @@ export function AppProvider(props: AppProviderProps) {
apiKey,
i18n,
isEmbeddedApp = true,
linkComponent = RemixPolarisLink,
__APP_BRIDGE_URL = APP_BRIDGE_URL,
...polarisProps
} = props;
Expand All @@ -141,7 +162,7 @@ export function AppProvider(props: AppProviderProps) {
{isEmbeddedApp && <script src={__APP_BRIDGE_URL} data-api-key={apiKey} />}
<PolarisAppProvider
{...polarisProps}
linkComponent={RemixPolarisLink}
linkComponent={linkComponent}
i18n={i18n || englishI18n}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ describe('<AppProvider />', () => {
});
});

it('forwards a custom linkComponent to the Polaris provider', () => {
// GIVEN a consumer-supplied link component (e.g. Remix `NavLink`)
const CustomLink = (props: any) => <a {...props} />;

// WHEN
const component = mount(
<AppProvider {...defaultProps} linkComponent={CustomLink}>
Hello world
</AppProvider>,
);

// 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(
<AppProvider isEmbeddedApp apiKey={'test-api-key'}>
Expand Down
Loading