--- title: Build a date picker for a specific shipping rate description: Use checkout UI extensions to collect a delivery date for a specific shipping rate. source_url: html: https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/date-picker md: https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/date-picker.md --- # Build a date picker for a specific shipping rate Collecting extra information in relation to specific shipping rates, like a preferred delivery date, is a common situation. In this tutorial, you'll use [checkout UI extensions](https://shopify.dev/docs/api/checkout-ui-extensions) to collect a delivery date for a specific shipping rate. Plus [Checkout UI extensions](https://shopify.dev/docs/api/checkout-ui-extensions) are available only to stores on a [Shopify Plus](https://www.shopify.com/plus) plan. ![Screenshot showing date pickers for both non-split and split shipping scenarios](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/images/apps/selected-date-picker-DKAHrVis.png) ## What you'll learn In this tutorial, you'll learn how to do the following tasks: * Generate a checkout UI extension, using Shopify CLI. * Configure your checkout UI extension in the [extension TOML](https://shopify.dev/docs/api/checkout-ui-extensions/latest/configuration) file. * Query the [Storefront API](https://shopify.dev/docs/api/storefront) from the extension code to get shipping rate data. * Use the [Polaris web component library](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components) to add new user interface to the checkout. * Use the [checkout UI extension API](https://shopify.dev/docs/api/checkout-ui-extensions#extension-apis) to read and write order information. * Save the date to a metafield and display the value in the Shopify admin. ## Requirements * You're a [user with app development permissions](https://shopify.dev/docs/apps/build/dev-dashboard/user-permissions). * You've created a new [development store](https://shopify.dev/docs/api/development-stores) with the following: * [Generated test data](https://shopify.dev/docs/api/development-stores/generated-test-data) * [Checkout and Customer Accounts Extensibility](https://shopify.dev/docs/api/developer-previews#checkout-and-customer-accounts-extensibility-developer-preview) feature preview enabled * You've [created an app that uses Shopify CLI 3.85.1 or higher](https://shopify.dev/docs/apps/build/scaffold-app). - You've reviewed the [UX guidelines](https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/ux-for-delivery-methods) for customizing delivery methods. ## Project [View on GitHub](https://github.com/Shopify/example-checkout--date-picker-shipping-rate--preact) ## Create a checkout UI extension To create a checkout UI extension, you'll use Shopify CLI, which generates starter code for building your extension. To create a checkout 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 checkout UI extension: ## Terminal ```terminal shopify app generate extension --template checkout_ui --name my-checkout-ui-extension ``` 1) Select `Checkout UI`. You should now have a new extension directory in your app's directory. The extension directory includes the extension script at `src/Checkout.jsx`. The following is an example directory structure: ## Checkout UI extension file structure ```text └── my-app └── extensions └── my-checkout-ui-extension ├── src │ └── Checkout.jsx OR Checkout.js // The index page of the checkout UI extension ├── locales │ ├── en.default.json // The default locale for the checkout UI extension │ └── fr.json // The locale file for non-regional French translations ├── shopify.extension.toml // The config file for the checkout 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 an extension target Set up a target for your checkout UI extension. [Targets](https://shopify.dev/docs/api/checkout-extensions/checkout#extension-targets) control where your extension renders in the checkout flow. ### Render the extension from your script file In your Checkout.jsx file, render the extension so it can be referenced in your configuration. *** This example code uses the [`purchase.checkout.shipping-option-list.render-after`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/extensiontargets) extension target, so it renders the extension after the shipping methods section on the shipping step of the checkout. You can [update the checkout URL](https://shopify.dev/docs/apps/build/checkout/test-checkout-ui-extensions#dynamic-extension-points) to test the extension in different locations in the checkout. ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` #### Reference the extension targets in your configuration file You can define more than one target so that app users can add the extension to multiple locations in the checkout. In your checkout UI extension's configuration file, for each of your targets, create an `[[extensions.targeting]]` section with the following information: * `module`: The path to the file that contains the extension code. * `target`: An identifier that specifies where you're injecting code into Shopify. *** [`shopify.extension.toml`](https://shopify.dev/docs/apps/build/app-extensions/configure-app-extensions) is the configuration file for your extension. It contains basic information and settings. Note Whenever you edit your extension configuration file, you need to restart your server for the changes to take effect. ## Terminal ```bash shopify app dev ``` ## /extensions/example-date-picker/shopify.extension.toml ```toml # Learn more about configuring your checkout UI extension: # https://shopify.dev/api/checkout-extensions/checkout/configuration # The version of APIs your extension will receive. Learn more: # https://shopify.dev/docs/api/usage/versioning api_version = "2025-10" [[extensions]] name = "example-date-picker" handle = "example-date-picker" type = "ui_extension" uid = "09980146-64fb-df11-8340-efa27fa6cd5da54311de" # Controls where in Shopify your extension will be injected, # and the file that contains your extension’s source code. Learn more: # https://shopify.dev/docs/api/checkout-ui-extensions/unstable/extension-targets-overview [[extensions.targeting]] module = "./src/Checkout.jsx" target = "purchase.checkout.shipping-option-list.render-after" [extensions.capabilities] # Gives your extension access to directly query Shopify’s storefront API. # https://shopify.dev/docs/api/checkout-ui-extensions/unstable/configuration#api-access api_access = true ``` ### Render the date picker and set the constraints In this step, you'll render a calendar where customers can select a delivery date, which is then saved to a `metafield`. The DatePicker component will display the available dates. #### Set up a metafield In this step, you'll set a namespace and key for the metafield where you want to store the custom field value. Later, you'll expose values stored in this metafield to merchants in the Shopify admin. A [metafield](https://shopify.dev/docs/apps/build/custom-data/metafields/manage-metafields) is a custom field that you can use to store additional information about a Shopify resource. You can use metafields to store information specific to your app without setting up your own storage. ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` #### Render the date picker In this step, you'll render a calendar where customers can select a delivery date. The `DatePicker` component will display the available dates. [Date​Picker](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components/forms/datepicker)[Heading](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components/typography/heading) ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` #### Set the constraints for the Date​Picker component If there are only certain dates that delivery can happen, then you can customize how the DatePicker component can be used by buyers by passing disabled dates through `disallow` and `disallowDates` properties. ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` #### Store the user input in the metafield You can use the [`applyMetafieldChange`](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/metafields#checkoutapi-propertydetail-applymetafieldchange) method to store the value that the customer enters in the `metafields` property of the checkout. This metafield value is later associated with the order. `applyMetafieldChange` is part of the [Metafields API](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/metafields). To learn more about it and other available APIs, refer to the [Checkout UI Extension APIs reference](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis). ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` #### Limit the Date​Picker component to a specific shipping rate If you want to limit the DatePicker component to a specific shipping rate, you can use the [Delivery API](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/delivery) to get the shipping rate data and then limit the render of the DatePicker component. [target](https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/delivery#shippingoptionlistapi-propertydetail-target) ## /extensions/example-date-picker/src/Checkout.jsx ```jsx import '@shopify/ui-extensions/preact'; import {render} from "preact"; import { useState, useCallback, useMemo } from "preact/hooks"; export default function() { render(, document.body) } function Extension() { const [selectedDate, setSelectedDate] = useState(""); const [yesterday, setYesterday] = useState(""); // Set a function to handle updating a metafield const { applyMetafieldChange } = shopify; const metafieldNamespace = "yourAppNamespace"; const metafieldKey = "deliverySchedule"; // Sets the selected date to today, unless today is Sunday, then it sets it to tomorrow useMemo(() => { let today = new Date(); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const deliveryDate = today.getDay() === 0 ? tomorrow : today; setSelectedDate(formatDate(deliveryDate)); setYesterday(formatDate(yesterday)); }, []); const handleChangeDate = useCallback((event) => { const selectedDate = event.target.value; setSelectedDate(selectedDate); applyMetafieldChange({ type: "updateMetafield", namespace: metafieldNamespace, key: metafieldKey, valueType: "string", value: selectedDate, }); }, []); const deliveryGroupList = shopify.target.value; /* Guard against duplicate rendering of `shipping-option-list.render-after` target for one-time purchase and subscription sections. * Calling `applyMetafieldChange()` on the same namespace-key pair from duplicated extensions would otherwise cause an overwrite of the metafield value. * Instead of guarding, another approach would be to prefix the metafield key when calling `applyMetafieldChange()`. * The Delivery Group List's (shopify.target.value) `groupType` could be used to such effect. */ if (!deliveryGroupList || deliveryGroupList.groupType !== 'oneTimePurchase') { return null; } const { deliveryGroups } = deliveryGroupList; let isExpressSelected = () => { const expressHandles = new Set( deliveryGroups .map( ({deliveryOptions}) => deliveryOptions.find(({ title }) => title === "Express")?.handle, ) .filter(Boolean), ); return deliveryGroups.some(({ selectedDeliveryOption }) => expressHandles.has(selectedDeliveryOption?.handle), ); }; return (isExpressSelected() ? ( <> Select a date for delivery ) : null); } const formatDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }; ``` ### Show the selected date in the Shopify admin After you've saved the date picker metafield to the order, you can display it on the order details page in the Shopify admin so that merchants can view it. #### Add a metafield definition for orders In the Shopify admin, add a [metafield definition](https://help.shopify.com/manual/custom-data/metafields/metafield-definitions) for orders. Use the same `namespace` and `key` as defined in your `/src/Checkout.jsx` file. Tip If you already placed an order with delivery instructions, then you might need to select the metafield from the [Metafields without a definition list](https://help.shopify.com/en/manual/custom-data/metafields/metafield-definitions/migrating-metafields-to-a-definition?shpxid=4309edbb-6287-4D20-599D-144372A27C83#definitions-for-existing-metafields). ### Preview 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. Make sure that you select a development store that has enabled the feature preview for [Checkout and Customer Accounts Extensibility](https://shopify.dev/docs/api/developer-previews#checkout-and-customer-accounts-extensibility-developer-preview). 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. Press `p` to open the developer console. 4. In the developer console page, click on the preview link for the custom date picker extension. The checkout opens. *** This section describes how to solve some potential errors when you run `dev` for an app that contains a checkout UI extension. ### Property token error If you receive the error `ShopifyCLI:AdminAPI requires the property token to be set`, then you'll need to use the [`--checkout-cart-url` flag](https://shopify.dev/docs/api/shopify-cli/app/app-dev#flags) to direct Shopify CLI to open a checkout session for you. ## Terminal ```terminal shopify app dev --checkout-cart-url cart/{product_variant_id}:{quantity} ``` ### Missing checkout link If you don't receive the test checkout URL when you run `dev`, then verify the following: * You have a development store populated with products. * You're logged in to the correct Partners organization and development store. To verify, check your app info using the following command: ## Terminal ```terminal shopify app info ``` Otherwise, you can manually create a checkout with the following steps: 1. From your development store's storefront, add some products to your cart. 2. From the cart, click **Checkout**. 3. From directory of the app that contains your extension, run `dev` to preview your app: ## Terminal ```terminal shopify app dev ``` 4. On the checkout page for your store, change the URL by appending the `?dev=https://{tunnel_url}/extensions` query string and reload the page. The `tunnel_url` parameter allows your app to be accessed using a unique HTTPS URL. You should now see a rendered order note that corresponds to the code in your project template. ### Test the extension functionality Test your extension to make sure that it works as expected by placing an order with delivery instructions in checkout. 1. With your server running, open the storefront of your development store. 2. Add a product to the cart and then check out. 3. Fill out the contact and shipping address information, and then move to the **Shipping** step of the checkout. 4. Select **Express Shipping**. A date picker appears. 5. Select a date and then complete the checkout. 6. In the Shopify admin for the development store, open the order details page for the order that you just placed. The delivery date that you entered is displayed in the **Metafields** section, with the delivery date field that you created. ![The Date Picker extension in both non-split and split shipping scenarios](https://cdn.shopify.com/shopifycloud/shopify-dev/production/assets/assets/images/apps/selected-date-picker-DKAHrVis.png) When you're ready to release your changes to users, you can create and release an [app version](https://shopify.dev/docs/apps/launch/deployment/app-versions). An app version is a snapshot of your app configuration and all extensions. 1. Navigate to your app directory. 2. Run the following command. Optionally, you can provide a name or message for the version using the `--version` and `--message` flags. ## Terminal ```terminal shopify app deploy ``` Releasing an app version replaces the current active version that's served to stores that have your app installed. It might take several minutes for app users to be upgraded to the new version. Tip If you want to create a version, but avoid releasing it to users, then run the `deploy` command with a `--no-release` flag. You can release the unreleased app version using Shopify CLI's [`release`](https://shopify.dev/docs/api/shopify-cli/app/app-release) command, or through the Dev Dashboard. ## /extensions/example-date-picker/shopify.extension.toml ```toml # Learn more about configuring your checkout UI extension: # https://shopify.dev/api/checkout-extensions/checkout/configuration # The version of APIs your extension will receive. Learn more: # https://shopify.dev/docs/api/usage/versioning api_version = "2025-10" [[extensions]] name = "example-date-picker" handle = "example-date-picker" type = "ui_extension" uid = "09980146-64fb-df11-8340-efa27fa6cd5da54311de" # Controls where in Shopify your extension will be injected, # and the file that contains your extension’s source code. Learn more: # https://shopify.dev/docs/api/checkout-ui-extensions/unstable/extension-targets-overview [[extensions.targeting]] module = "./src/Checkout.jsx" target = "purchase.checkout.shipping-option-list.render-after" [extensions.capabilities] # Gives your extension access to directly query Shopify’s storefront API. # https://shopify.dev/docs/api/checkout-ui-extensions/unstable/configuration#api-access 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/heart.png)![](https://shopify.dev/images/icons/32/heart-dark.png)](https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/ux-for-delivery-methods) [Review delivery method UX guidelines](https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/ux-for-delivery-methods) [Build a good delivery method experience by following our UX guidelines.](https://shopify.dev/docs/apps/build/checkout/delivery-shipping/delivery-methods/ux-for-delivery-methods) [![](https://shopify.dev/images/icons/32/globe.png)![](https://shopify.dev/images/icons/32/globe-dark.png)](https://shopify.dev/docs/apps/checkout/localizing-ui-extensions) [Localize your extension](https://shopify.dev/docs/apps/checkout/localizing-ui-extensions) [Learn how to localize the text and number formats in your extension.](https://shopify.dev/docs/apps/checkout/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/checkout-ui-extensions/latest/components) [Explore the Polaris web components reference](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components) [Learn about all of the components that you can use in your checkout UI extension.](https://shopify.dev/docs/api/checkout-ui-extensions/latest/components) [![](https://shopify.dev/images/icons/32/blocks.png)![](https://shopify.dev/images/icons/32/blocks-dark.png)](https://shopify.dev/docs/api/checkout-ui-extensions#extension-targets) [Explore the checkout UI extension targets](https://shopify.dev/docs/api/checkout-ui-extensions#extension-targets) [Learn about the extension targets offered in the checkout.](https://shopify.dev/docs/api/checkout-ui-extensions#extension-targets)