The API provided to extensions to navigate to extensions or host page.
import {
reactExtension,
useApi,
Button,
} from '@shopify/ui-extensions-react/customer-account';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const {navigation} = useApi();
return (
<Button
onPress={() => {
navigation.navigate('extension://orders');
}}
>
Navigate to orders path
</Button>
);
}
import {
extend,
Button,
} from '@shopify/customer-account-ui-extensions';
export default extend(
'customer-account.page.render',
(root, {navigation}) => {
const button = root.createComponent(
Button,
{
onPress: () => {
navigation.navigate(
'extension://orders',
);
},
},
'Navigate to orders path',
);
root.appendChild(button);
},
);
Navigation API for all extensions. [Refer to supported protocols](/docs/api/customer-account-ui-extensions/2024-10#custom-protocols)
The navigate() method navigates to a specific URL, updating any provided state in the history entries list.
export interface NavigateFunction { /** * Navigates to a specific URL, updating any provided state in the history entries list. * @param url The destination URL to navigate to. */ (url: string, options?: NavigationOptions): void; }
Only available for full-page extension `customer-account.page.render`
The currentEntry read-only property of the Navigation interface returns a NavigationHistoryEntry object representing the location the user is currently navigated to right now.
The navigate() method navigates to a specific URL, updating any provided state in the history entries list.
The updateCurrentEntry() method of the Navigation interface updates the state of the currentEntry; used in cases where the state change will be independent of a navigation or reload.
The NavigationCurrentEntryChangeEvent interface of the Navigation API is the event object for the currententrychange event, which fires when the Navigation.currentEntry has changed.
Returns the NavigationHistoryEntry that was navigated from.
Returns the type of the navigation that resulted in the change.
The NavigationHistoryEntry interface of the Navigation API represents a single navigation history entry.
Returns a clone of the available state associated with this history entry.
Returns the key of the history entry. This is a unique, UA-generated value that represents the history entry's slot in the entries list rather than the entry itself.
Returns the URL of this history entry.
An enumerated value representing the type of navigation.
'push' | 'replace' | 'traverse'
export interface NavigateFunction { /** * Navigates to a specific URL, updating any provided state in the history entries list. * @param url The destination URL to navigate to. */ (url: string, options?: NavigationOptions): void; }
Returns the live navigation current entry
export function useNavigationCurrentEntry< Target extends RenderCustomerAccountFullPageExtensionTarget = RenderCustomerAccountFullPageExtensionTarget, >(): NavigationHistoryEntry { const {currentEntry, removeEventListener, addEventListener} = useApi<Target>().navigation; const [entry, update] = useReducer(() => currentEntry, currentEntry); useEffect(() => { if (!currentEntry || !removeEventListener || !addEventListener) { throw new Error( 'useNavigationCurrentEntry must be used in an extension with the customer-account.page.render or customer-account.order.page.render target only', ); } addEventListener('currententrychange', update); return () => removeEventListener('currententrychange', update); }, [addEventListener, currentEntry, removeEventListener]); return entry; }
The NavigationHistoryEntry interface of the Navigation API represents a single navigation history entry.
Returns a clone of the available state associated with this history entry.
Returns the key of the history entry. This is a unique, UA-generated value that represents the history entry's slot in the entries list rather than the entry itself.
Returns the URL of this history entry.
The API provided to extensions to navigate to extensions or host page.
import React, {
useEffect,
useState,
useCallback,
} from 'react';
import {
reactExtension,
useApi,
BlockStack,
Heading,
Image,
ResourceItem,
Text,
} from '@shopify/ui-extensions-react/customer-account';
import type {NavigationCurrentEntryChangeEvent} from '@shopify/ui-extensions/customer-account';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const {navigation} = useApi();
const [currentEntryState, setCurrentEntry] =
useState<NavigationCurrentEntryChangeEvent>();
const updateCurrentEntryState = useCallback(
(
event: NavigationCurrentEntryChangeEvent,
) => {
setCurrentEntry(event);
},
[],
);
useEffect(() => {
navigation.addEventListener(
'currententrychange',
updateCurrentEntryState,
);
return () => {
navigation.removeEventListener(
'currententrychange',
updateCurrentEntryState,
);
};
}, [updateCurrentEntryState, navigation]);
function getWishlistId(_url: string): string {
throw new Error('Function not implemented.');
}
const wishlistIdPattern =
/^extension:\/wishlists\/(\d+)$/;
const wishlistDetailsMatch =
navigation.currentEntry.url.match(
wishlistIdPattern,
);
if (
navigation.currentEntry.url === 'extension:/'
) {
return <Wishlists />;
} else if (wishlistDetailsMatch) {
return (
<WishlistDetails
id={getWishlistId(
wishlistDetailsMatch[1],
)}
/>
);
} else {
return <NotFound />;
}
}
interface WishlistDetailsProps {
id: string;
}
interface Wishlist {
id: string;
items: {
productId: string;
productLink: string;
productImage: string;
label: string;
}[];
}
function Wishlists() {
const [wishlists, setWishlists] =
useState<Wishlist[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlists() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists`,
);
const wishlists = await response.json();
setLoading(false);
setWishlists(wishlists);
}
void fetchWishlists();
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlists) {
return <NotFound />;
}
return (
<BlockStack>
{wishlists.map((item) => {
return (
<ResourceItem
to={`/wishlist/${item.id}`}
key={item.id}
>
<BlockStack>
<Image
source={
item.items[0].productImage
}
/>
<Text>{item.items[0].label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function WishlistDetails({
id,
}: WishlistDetailsProps) {
const [wishlist, setWishlist] =
useState<Wishlist>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlist() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists/${id}`,
);
const wishlist = await response.json();
setLoading(false);
setWishlist(wishlist);
}
void fetchWishlist();
}, [id]);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlist) {
return <NotFound />;
}
return (
<BlockStack>
{wishlist.items.map((item) => {
return (
<ResourceItem
to={`/wishlist/${id}/${item.productId}`}
key={item.productId}
>
<BlockStack>
<Image source={item.productImage} />
<Text>{item.label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function NotFound() {
return (
<BlockStack>
<Heading>Resource Not found</Heading>
</BlockStack>
);
}
import React, {
useEffect,
useState,
useCallback,
} from 'react';
import {
reactExtension,
useApi,
BlockStack,
Heading,
Image,
ResourceItem,
Text,
} from '@shopify/ui-extensions-react/customer-account';
import type {NavigationCurrentEntryChangeEvent} from '@shopify/ui-extensions/customer-account';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const {navigation} = useApi();
const [currentEntryState, setCurrentEntry] =
useState<NavigationCurrentEntryChangeEvent>();
const updateCurrentEntryState = useCallback(
(
event: NavigationCurrentEntryChangeEvent,
) => {
setCurrentEntry(event);
},
[],
);
useEffect(() => {
navigation.addEventListener(
'currententrychange',
updateCurrentEntryState,
);
return () => {
navigation.removeEventListener(
'currententrychange',
updateCurrentEntryState,
);
};
}, [updateCurrentEntryState, navigation]);
function getWishlistId(_url: string): string {
throw new Error('Function not implemented.');
}
const wishlistIdPattern =
/^extension:\/wishlists\/(\d+)$/;
const wishlistDetailsMatch =
navigation.currentEntry.url.match(
wishlistIdPattern,
);
if (
navigation.currentEntry.url === 'extension:/'
) {
return <Wishlists />;
} else if (wishlistDetailsMatch) {
return (
<WishlistDetails
id={getWishlistId(
wishlistDetailsMatch[1],
)}
/>
);
} else {
return <NotFound />;
}
}
interface WishlistDetailsProps {
id: string;
}
interface Wishlist {
id: string;
items: {
productId: string;
productLink: string;
productImage: string;
label: string;
}[];
}
function Wishlists() {
const [wishlists, setWishlists] =
useState<Wishlist[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlists() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists`,
);
const wishlists = await response.json();
setLoading(false);
setWishlists(wishlists);
}
void fetchWishlists();
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlists) {
return <NotFound />;
}
return (
<BlockStack>
{wishlists.map((item) => {
return (
<ResourceItem
to={`/wishlist/${item.id}`}
key={item.id}
>
<BlockStack>
<Image
source={
item.items[0].productImage
}
/>
<Text>{item.items[0].label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function WishlistDetails({
id,
}: WishlistDetailsProps) {
const [wishlist, setWishlist] =
useState<Wishlist>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlist() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists/${id}`,
);
const wishlist = await response.json();
setLoading(false);
setWishlist(wishlist);
}
void fetchWishlist();
}, [id]);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlist) {
return <NotFound />;
}
return (
<BlockStack>
{wishlist.items.map((item) => {
return (
<ResourceItem
to={`/wishlist/${id}/${item.productId}`}
key={item.productId}
>
<BlockStack>
<Image source={item.productImage} />
<Text>{item.label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function NotFound() {
return (
<BlockStack>
<Heading>Resource Not found</Heading>
</BlockStack>
);
}
import React, {
useEffect,
useState,
} from 'react';
import {
reactExtension,
BlockStack,
Heading,
Image,
ResourceItem,
Text,
useNavigationCurrentEntry,
} from '@shopify/ui-extensions-react/customer-account';
import type {NavigationCurrentEntryChangeEvent} from '@shopify/ui-extensions/customer-account';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const currentEntry = useNavigationCurrentEntry();
function getWishlistId(_url: string): string {
throw new Error('Function not implemented.');
}
const wishlistIdPattern =
/^extension:\/wishlists\/(\d+)$/;
const wishlistDetailsMatch =
currentEntry.url.match(
wishlistIdPattern,
);
if (
currentEntry.url === 'extension:/'
) {
return <Wishlists />;
} else if (wishlistDetailsMatch) {
return (
<WishlistDetails
id={getWishlistId(
wishlistDetailsMatch[1],
)}
/>
);
} else {
return <NotFound />;
}
}
interface WishlistDetailsProps {
id: string;
}
interface Wishlist {
id: string;
items: {
productId: string;
productLink: string;
productImage: string;
label: string;
}[];
}
function Wishlists() {
const [wishlists, setWishlists] =
useState<Wishlist[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlists() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists`,
);
const wishlists = await response.json();
setLoading(false);
setWishlists(wishlists);
}
void fetchWishlists();
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlists) {
return <NotFound />;
}
return (
<BlockStack>
{wishlists.map((item) => {
return (
<ResourceItem
to={`/wishlist/${item.id}`}
key={item.id}
>
<BlockStack>
<Image
source={
item.items[0].productImage
}
/>
<Text>{item.items[0].label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function WishlistDetails({
id,
}: WishlistDetailsProps) {
const [wishlist, setWishlist] =
useState<Wishlist>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlist() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists/${id}`,
);
const wishlist = await response.json();
setLoading(false);
setWishlist(wishlist);
}
void fetchWishlist();
}, [id]);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlist) {
return <NotFound />;
}
return (
<BlockStack>
{wishlist.items.map((item) => {
return (
<ResourceItem
to={`/wishlist/${id}/${item.productId}`}
key={item.productId}
>
<BlockStack>
<Image source={item.productImage} />
<Text>{item.label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function NotFound() {
return (
<BlockStack>
<Heading>Resource Not found</Heading>
</BlockStack>
);
}
import React, {
useEffect,
useState,
} from 'react';
import {
reactExtension,
BlockStack,
Heading,
Image,
ResourceItem,
Text,
useNavigationCurrentEntry,
} from '@shopify/ui-extensions-react/customer-account';
import type {NavigationCurrentEntryChangeEvent} from '@shopify/ui-extensions/customer-account';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const currentEntry = useNavigationCurrentEntry();
function getWishlistId(_url: string): string {
throw new Error('Function not implemented.');
}
const wishlistIdPattern =
/^extension:\/wishlists\/(\d+)$/;
const wishlistDetailsMatch =
currentEntry.url.match(
wishlistIdPattern,
);
if (
currentEntry.url === 'extension:/'
) {
return <Wishlists />;
} else if (wishlistDetailsMatch) {
return (
<WishlistDetails
id={getWishlistId(
wishlistDetailsMatch[1],
)}
/>
);
} else {
return <NotFound />;
}
}
interface WishlistDetailsProps {
id: string;
}
interface Wishlist {
id: string;
items: {
productId: string;
productLink: string;
productImage: string;
label: string;
}[];
}
function Wishlists() {
const [wishlists, setWishlists] =
useState<Wishlist[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlists() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists`,
);
const wishlists = await response.json();
setLoading(false);
setWishlists(wishlists);
}
void fetchWishlists();
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlists) {
return <NotFound />;
}
return (
<BlockStack>
{wishlists.map((item) => {
return (
<ResourceItem
to={`/wishlist/${item.id}`}
key={item.id}
>
<BlockStack>
<Image
source={
item.items[0].productImage
}
/>
<Text>{item.items[0].label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function WishlistDetails({
id,
}: WishlistDetailsProps) {
const [wishlist, setWishlist] =
useState<Wishlist>();
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchWishlist() {
setLoading(true);
const response = await fetch(
`https://your-backend.com/api/wishlists/${id}`,
);
const wishlist = await response.json();
setLoading(false);
setWishlist(wishlist);
}
void fetchWishlist();
}, [id]);
if (loading) {
return <Text>Loading...</Text>;
}
if (!wishlist) {
return <NotFound />;
}
return (
<BlockStack>
{wishlist.items.map((item) => {
return (
<ResourceItem
to={`/wishlist/${id}/${item.productId}`}
key={item.productId}
>
<BlockStack>
<Image source={item.productImage} />
<Text>{item.label}</Text>
</BlockStack>
</ResourceItem>
);
})}
</BlockStack>
);
}
function NotFound() {
return (
<BlockStack>
<Heading>Resource Not found</Heading>
</BlockStack>
);
}
import {
reactExtension,
useApi,
Page,
Button,
} from '@shopify/customer-account-ui-extensions-react';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const { navigation } = useApi();
return (
<Page
title="Wishlist"
secondaryAction={
<Button
onPress={navigation.navigate(
'shopify:customer-account/orders',
)}
>
Back to orders index
</Button>
}
>
<p>Wishlist content</p>
</Page>
);
}
import {
reactExtension,
useApi,
Page,
Button,
} from '@shopify/customer-account-ui-extensions-react';
export default reactExtension(
'customer-account.page.render',
() => <App />,
);
function App() {
const { navigation } = useApi();
return (
<Page
title="Wishlist"
secondaryAction={
<Button
onPress={navigation.navigate(
'shopify:customer-account/orders',
)}
>
Back to orders index
</Button>
}
>
<p>Wishlist content</p>
</Page>
);
}