--- title: Build new pages in customer accounts description: Learn how to build a full-page extension for customer wishlists, using customer account UI extensions. source_url: html: https://shopify.dev/docs/apps/build/customer-accounts/full-page-extensions/build-new-pages md: https://shopify.dev/docs/apps/build/customer-accounts/full-page-extensions/build-new-pages.md --- # Build new pages in customer accounts Full-page UI extensions enable you to create a page within the customer account experience while preserving a merchant's branding. In this tutorial, you'll learn how to create a standalone full-page UI extension that customers can access without leaving their account or needing to log in again. ## What you'll learn In this tutorial, you'll learn how to do the following tasks: * Create a full-page UI extension in customer accounts * Create a full-page extension entry point to test your full-page extension * Use Polaris web components like [`s-page`](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/structure/page) and [`s-section`](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/structure/section) to build a page for customer wishlists * Query the [Storefront API](https://shopify.dev/docs/api/storefront) to retrieve a list of products * Navigate to your full-page extension * Run the extension locally and test it on a development store ## Requirements [Create a Partner account](https://www.shopify.com/partners) [Create a development store](https://shopify.dev/docs/apps/tools/development-stores) The development store should be pre-populated with [test data](https://shopify.dev/docs/api/development-stores/generated-test-data), including an order associated with the email address you'll use to log in to the customer account experience. [Shopify CLI](https://shopify.dev/docs/apps/tools/cli/installation) You'll need to use the [latest version of Shopify CLI](https://shopify.dev/docs/api/shopify-cli#upgrade). [Scaffold an app](https://shopify.dev/docs/apps/build/scaffold-app) Scaffold an app that uses Shopify CLI. ## Project [View on GitHub](https://github.com/Shopify/customer-account-tutorials/tree/main/preact/example-customer-account--wishlist--preact) ### Create a customer account UI extension for the full-page target To create a customer account UI extension, you can use Shopify CLI, which generates starter code for building your extension and automates common development tasks. 1. Navigate to your app directory: ## Terminal ```terminal cd ``` 2. Run the following command to create a new customer account UI extension: ## Terminal ```terminal shopify app generate extension --template customer_account_ui --name customer-account-ui-extension ``` You should now have a new extension directory in your app's directory. The extension directory includes the extension script at `src/{FileName}.jsx`. The following is an example directory structure: ## Customer account UI extension file structure ```text └── my-app └── extensions └── my-customer-account-ui-extension ├── src │ └── CustomerAccount.jsx // The index page of the customer account UI extension ├── locales │ ├── en.default.json // The default locale for the customer account UI extension │ └── fr.json // The locale file for non-regional French translations ├── shopify.extension.toml // The config file for the customer account UI extension └── package.json ``` 1) Start your development server to build and preview your app: ## Terminal ```terminal shopify app dev ``` To learn about the processes that are executed when you run `dev`, refer to the [Shopify CLI command reference](https://shopify.dev/docs/api/shopify-cli/app/app-dev). 2) Press `p` to open the developer console. In the developer console page, click on the preview link for your extension. ### Set up the target for your full-page extension Set up the targets for your customer account UI extension. [Targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) control where your extension renders in the account. A full-page extension target cannot coexist with any other targets in the same extension. In this example, you'll create a page that lists products that were added to a customer's wishlist, and a link to that page. #### Reference the extension targets in your configuration file This example code uses the `customer-account.page.render` target. In your extension's [`shopify.extension.toml`](https://shopify.dev/docs/apps/build/app-extensions/configure-app-extensions) configuration file, for each of the targets, create an `[[extensions.targeting]]` section with the following information: * **`target`**: An identifier that specifies where you're injecting code into Shopify. * **`module`**: The path to the file that contains the extension code. *** [customer-account.page.render](https://shopify.dev/docs/api/customer-account-ui-extensions/targets/full-page/customer-account-page-render) ## /preact/example-customer-account--wishlist--preact/extensions/customer-account-wishlist-extension/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "3a495b4c-7432-f824-50b6-44ec8381c25e7d2a5779" type = "ui_extension" name = "My wishlist" handle = "wishlist-extension-preact" [[extensions.targeting]] module = "./src/FullPageExtension.jsx" target = "customer-account.page.render" [extensions.capabilities] api_access = true ``` #### Create files for your targets Create a file in your extension's `src` directory for each of your targets. In this example, you'll create a file for the profile block extension and a file for the full-page extension. The filenames must match the `module` paths you specified. ## /preact/example-customer-account--wishlist--preact/extensions/customer-account-wishlist-extension/src/FullPageExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useEffect, useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function FullPageExtension() { const [wishlist, setWishlist] = useState([]); const [loading, setLoading] = useState(false); const [removeLoading, setRemoveLoading] = useState({ id: null, loading: false, }); async function fetchWishlist() { setLoading(true); try { // Implement a server request to retrieve the wishlist for this customer // Then call the Storefront API to retrieve the details of the wishlisted products const data = await shopify.query( `query ($first: Int!) { products(first: $first) { nodes { id title onlineStoreUrl priceRange { minVariantPrice { amount currencyCode } } featuredImage { url } } } }`, { variables: {first: 10}, } ); setLoading(false); setWishlist(data.data?.products?.nodes || []); } catch (error) { setLoading(false); console.log(error); } } async function deleteWishlistItem(id) { // Simulate a server request setRemoveLoading({loading: true, id}); return new Promise((resolve) => { setTimeout(() => { // Send a request to your server to delete the wishlist item setWishlist(wishlist.filter((item) => item.id !== id)); setRemoveLoading({loading: false, id: null}); resolve(); }, 750); }); } useEffect(() => { fetchWishlist(); }, []); return ( {!loading && wishlist.length > 0 && wishlist.map((product) => { return ( {product.title} {shopify.i18n.formatCurrency( product.priceRange.minVariantPrice.amount, { currency: product.priceRange.minVariantPrice.currencyCode, } )} View product { deleteWishlistItem(product.id); }} > Remove ); })} {!loading && wishlist.length === 0 && ( No items in your wishlist. )} ); } ``` ### Create a customer account UI extension for the full-page entry point for testing Create an extension, to define an entry point to the full-page extension created above. To create a customer account UI extension, you can use Shopify CLI, which generates starter code for building your extension and automates common development tasks. 1. Navigate to your app directory: ## Terminal ```terminal cd ``` 2. Run the following command to create a new customer account UI extension: ## Terminal ```terminal shopify app generate extension --template customer_account_ui --name customer-account-ui-extension ``` You should now have a new extension directory in your app's directory. The extension directory includes the extension script at `src/{FileName}.jsx`. The following is an example directory structure: ## Customer account UI extension file structure ```text └── my-app └── extensions └── my-customer-account-ui-extension ├── src │ └── CustomerAccount.jsx // The index page of the customer account UI extension ├── locales │ ├── en.default.json // The default locale for the customer account UI extension │ └── fr.json // The locale file for non-regional French translations ├── shopify.extension.toml // The config file for the customer account UI extension └── package.json ``` 1) Start your development server to build and preview your app: ## Terminal ```terminal shopify app dev ``` To learn about the processes that are executed when you run `dev`, refer to the [Shopify CLI command reference](https://shopify.dev/docs/api/shopify-cli/app/app-dev). 2) Press `p` to open the developer console. In the developer console page, click on the preview link for your extension. ### Set up the extension target for your entry point Set up the extension target for your customer account UI extension. [Extension targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) control where your extension renders in the customer account flow. The example code uses the `customer-account.profile.block.render` target #### Add the `customer-account.profile.block.render` extension target to your configuration file In your extension's configuration file, for the `customer-account.profile.block.render` extension target, create an `[[extensions.targeting]]` section with the following information: **`target`**: An identifier that specifies where you're injecting code into Shopify. **`module`**: The path to the file that contains the extension code. ## /preact/example-customer-account--wishlist--preact/extensions/wishlist-profile-block/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "a1eb23c4-ce29-1e17-8061-132bf7a545b9d9bca54d" type = "ui_extension" name = "Upsell banner" handle = "wishlist-profile-block" [[extensions.targeting]] module = "./src/ProfileBlockExtension.jsx" target = "customer-account.profile.block.render" [extensions.capabilities] api_access = true ``` #### Create files for your targets Create a file in your extension's `src` directory for the extension target. In this example, you'll create a file for the profile block extension. Make sure that the name of the files match the `module` paths that you specified. [shopify.extension.toml](https://shopify.dev/docs/apps/build/app-extensions/configure-app-extensions) is the configuration file for your extension. *** [customer-account.profile.block.render](https://shopify.dev/docs/api/customer-account-ui-extensions/targets/profile-\(default\)/customer-account-profile-block-render) ## /preact/example-customer-account--wishlist--preact/extensions/wishlist-profile-block/src/ProfileBlockExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockExtension() { return ( Grow your garden with more plants from your wishlist. View wishlist ); } ``` ### Build the full-page extension #### Fetch the customer's wishlist Create an asynchronous function to fetch the wishlist from your server, and invoke it within a side effect. In this example, you'll retrieve the shop's first ten products from the [Storefront API](https://shopify.dev/docs/api/storefront). In a production-ready application, first retrieve the customer's wishlist from your server, and then retrieve the product details from the Storefront API. ## /preact/example-customer-account--wishlist--preact/extensions/customer-account-wishlist-extension/src/FullPageExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useEffect, useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function FullPageExtension() { const [wishlist, setWishlist] = useState([]); const [loading, setLoading] = useState(false); const [removeLoading, setRemoveLoading] = useState({ id: null, loading: false, }); async function fetchWishlist() { setLoading(true); try { // Implement a server request to retrieve the wishlist for this customer // Then call the Storefront API to retrieve the details of the wishlisted products const data = await shopify.query( `query ($first: Int!) { products(first: $first) { nodes { id title onlineStoreUrl priceRange { minVariantPrice { amount currencyCode } } featuredImage { url } } } }`, { variables: {first: 10}, } ); setLoading(false); setWishlist(data.data?.products?.nodes || []); } catch (error) { setLoading(false); console.log(error); } } async function deleteWishlistItem(id) { // Simulate a server request setRemoveLoading({loading: true, id}); return new Promise((resolve) => { setTimeout(() => { // Send a request to your server to delete the wishlist item setWishlist(wishlist.filter((item) => item.id !== id)); setRemoveLoading({loading: false, id: null}); resolve(); }, 750); }); } useEffect(() => { fetchWishlist(); }, []); return ( {!loading && wishlist.length > 0 && wishlist.map((product) => { return ( {product.title} {shopify.i18n.formatCurrency( product.priceRange.minVariantPrice.amount, { currency: product.priceRange.minVariantPrice.currencyCode, } )} View product { deleteWishlistItem(product.id); }} > Remove ); })} {!loading && wishlist.length === 0 && ( No items in your wishlist. )} ); } ``` #### Build the page UI In your full-page extension file, create a function to set up the page UI. To match the look and feel of the customer accounts experience, use the `s-page` and `s-section` components. *** ![Full-page extension](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/apps/customer-accounts/full-page-extensions/wishlist-DSGKRlUn.png) Customer account UI extensions are limited to specific UI components exposed by the platform [for security reasons](https://shopify.dev/docs/api/customer-account-ui-extensions#security). You can use checkout UI components and customer account UI components to create a UI that feels seamless within the customer accounts experience, and that inherits a merchant's brand settings. [s-page](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/structure/page)[s-grid](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/structure/grid)[s-section](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/structure/section)[s-image](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/media/image)[s-stack](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/structure/stack)[s-text](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/titles-and-text/text)[s-button](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/actions/button) ## /preact/example-customer-account--wishlist--preact/extensions/customer-account-wishlist-extension/src/FullPageExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; import {useEffect, useState} from 'preact/hooks'; export default async () => { render(, document.body); }; function FullPageExtension() { const [wishlist, setWishlist] = useState([]); const [loading, setLoading] = useState(false); const [removeLoading, setRemoveLoading] = useState({ id: null, loading: false, }); async function fetchWishlist() { setLoading(true); try { // Implement a server request to retrieve the wishlist for this customer // Then call the Storefront API to retrieve the details of the wishlisted products const data = await shopify.query( `query ($first: Int!) { products(first: $first) { nodes { id title onlineStoreUrl priceRange { minVariantPrice { amount currencyCode } } featuredImage { url } } } }`, { variables: {first: 10}, } ); setLoading(false); setWishlist(data.data?.products?.nodes || []); } catch (error) { setLoading(false); console.log(error); } } async function deleteWishlistItem(id) { // Simulate a server request setRemoveLoading({loading: true, id}); return new Promise((resolve) => { setTimeout(() => { // Send a request to your server to delete the wishlist item setWishlist(wishlist.filter((item) => item.id !== id)); setRemoveLoading({loading: false, id: null}); resolve(); }, 750); }); } useEffect(() => { fetchWishlist(); }, []); return ( {!loading && wishlist.length > 0 && wishlist.map((product) => { return ( {product.title} {shopify.i18n.formatCurrency( product.priceRange.minVariantPrice.amount, { currency: product.priceRange.minVariantPrice.currencyCode, } )} View product { deleteWishlistItem(product.id); }} > Remove ); })} {!loading && wishlist.length === 0 && ( No items in your wishlist. )} ); } ``` ### Add a link to your full-page extension In your profile block extension file, create a function to set up the link that routes to your full-page extension. Setting the `href` prop to `extension:wishlist-extension-preact/` instructs the router to navigate to the full-page extension that you created. *** ![Full page extension entry point](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/apps/customer-accounts/full-page-extensions/banner-aZiY3D2e.png) When navigating to a full-page extension from another extension within the same app, use the `extension:$full-page-extension-handle/` protocol. In a production-ready application, don't include this link in your extension. Instead, only publish the full-page extension. Merchants can add a link to it in the header navigation menu of their customer accounts experience. [s-section](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components/structure/section)[s-link](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/actions/link)[s-text](https://shopify.dev/docs/api/checkout-ui-extensions/polaris-web-components/titles-and-text/text) ## /preact/example-customer-account--wishlist--preact/extensions/wishlist-profile-block/src/ProfileBlockExtension.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from 'preact'; export default async () => { render(, document.body); }; function BlockExtension() { return ( Grow your garden with more plants from your wishlist. View wishlist ); } ``` ### Preview and test the extension Preview your extension to make sure that it works as expected. #### Start your server Run the Shopify CLI `dev` command to build your app and preview it on your development store. 1. In a terminal, navigate to your app directory. 2. Either start or restart your server to build and preview your app: ## Terminal ```bash shopify app dev ``` 3. If prompted, select a development store. 4. Press `p` to open the developer console. 5. In the developer console page, click the preview link for one of your extension targets. The customer accounts experience opens. #### Test the full-page extension 1. Navigate to the profile page by clicking the dropdown in the top right corner of the customer account and selecting **Profile**. 2. Click the **View wishlist** link in the banner that you created. You're taken to the full-page extension you created, which lists out the products that were added to the customer's wishlist. *** ![Full-page extension](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/apps/customer-accounts/full-page-extensions/wishlist-DSGKRlUn.png) ## /preact/example-customer-account--wishlist--preact/extensions/customer-account-wishlist-extension/shopify.extension.toml ```toml api_version = "2025-10" [[extensions]] uid = "3a495b4c-7432-f824-50b6-44ec8381c25e7d2a5779" type = "ui_extension" name = "My wishlist" handle = "wishlist-extension-preact" [[extensions.targeting]] module = "./src/FullPageExtension.jsx" target = "customer-account.page.render" [extensions.capabilities] api_access = true ``` ## Tutorial complete! Nice work - what you just built could be used by Shopify merchants around the world! Keep the momentum going with these related tutorials and resources. ### Next Steps [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [Extension placement](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [Explore extension placement options and make informed decisions on where to position them.](https://shopify.dev/docs/apps/customer-accounts/best-practices/deciding-extension-placement) [![](https://shopify.dev/images/icons/32/globe.png)![](https://shopify.dev/images/icons/32/globe-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [Localize your extension](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [Learn about localizing your customer account UI extensions for international merchants and customers.](https://shopify.dev/docs/apps/customer-accounts/best-practices/localizing-ui-extensions) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [Extension targets](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [Learn about the extension targets offered for customer accounts.](https://shopify.dev/docs/api/customer-account-ui-extensions/targets) [![](https://shopify.dev/images/icons/32/heart.png)![](https://shopify.dev/images/icons/32/heart-dark.png)](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [UX guidelines](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [Follow our UX guidelines for customer accounts to ensure a consistent and satisfying user experience.](https://shopify.dev/docs/apps/customer-accounts/best-practices/ux-guidelines) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [Polaris web components](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [Learn about the components you can use to build customer account UI extensions.](https://shopify.dev/docs/api/customer-account-ui-extensions/polaris-web-components) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/apps/build/customer-accounts/editor-extension-collections) [Editor extension collections](https://shopify.dev/docs/apps/build/customer-accounts/editor-extension-collections) [Learn how to create editor extension collections to group related extensions.](https://shopify.dev/docs/apps/build/customer-accounts/editor-extension-collections)