import Deploy from 'app/views/partials/extensions/deploy.mdx'
import CheckoutUiRequirements from 'app/views/partials/apps/checkout/ui-extensions/requirements.mdx'
import CheckoutUiReference from 'app/views/partials/apps/checkout/ui-extensions/reference.mdx'
import CheckoutUiTroubleshooting from 'app/views/partials/apps/checkout/ui-extensions/troubleshooting.mdx'
import CheckoutUiPreview from 'app/views/partials/apps/checkout/ui-extensions/preview.mdx'
import CheckoutUiCreate from 'app/views/partials/apps/checkout/ui-extensions/create.mdx'
<Repo extension="react" href="https://github.com/Shopify/example-checkout--client-validation--react" />
<Repo extension="javascript" href="https://github.com/Shopify/example-checkout--client-validation--js" />
<Picker name="extension">
<PickerOption name="react" />
<PickerOption name="javascript" />
</Picker>
<Overview>
<Notice type="note">
Blocking checkout progress behavior doesn't apply to express checkout options, such as Shop Pay, Google Pay, and Apple Pay.
</Notice>
You can block customers from progressing through the checkout based on information that they provide. For example, you might want to block the checkout based on the age or address entered by the customer.
This tutorial uses [checkout UI extensions](/docs/api/checkout-ui-extensions/) to collect input and validate it.
Using the `buyerJourney` intercept and `block_progress` capabilities, customers are blocked from progressing in checkout and shown a validation error. The extension UI adjusts to handle cases where the user doesn't allow the extension to block the checkout progress.
This tutorial explains the process to validate a customer's age, but you can use it as an example to build other customizations for field validation, such as the following:
- Address
- Tax code
- Phone number
- PO box address
- Name
Follow along with this tutorial to build a sample app, or clone the completed sample app.
<Notice type="shopifyPlus" title="Shopify Plus">
Checkout UI extensions are available only to [Shopify Plus](https://www.shopify.com/plus) merchants.
</Notice>
<video autoplay muted loop controls>
<source src="/assets/apps/checkout/validation/validate-fields.webm" type="video/webm" />
<source src="/assets/apps/checkout/validation/validate-fields.mp4" type="video/mp4" />
</video>
## What you'll learn
In this tutorial, you'll learn how to do the following:
- Generate a checkout UI extension that appears in the checkout flow using Shopify CLI.
- Set up the extension target and capabilities to block the checkout progress.
- Intercept and prevent a customer's progress through the checkout, and display an error message at the field and page level.
- Check whether you have the ability to block the checkout progress.
</Overview>
<Requirements>
<CheckoutUiRequirements />
</Requirements>
<StepSection>
<Step>
### Create a Checkout UI extension
To create a checkout UI extension, use Shopify CLI, which generates starter code for building your extension.
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" />
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" />
<CheckoutUiCreate />
</Substep>
</Step>
<Step>
### Set up an extension target and configure capabilities
Set up a target for your checkout UI extension. [Targets](/docs/api/checkout-extensions/checkout#extension-targets) control where your extension renders in the checkout flow.
In your extension configuration, add the optional capabilities that you want to use. Capabilities allow you to access additional functionality in your extension.
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.extension-point"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.extension-point"/>
#### Export the targets from your script file
In your <If extension="react">`Checkout.jsx`</If><If extension="javascript">`Checkout.js`</If> file, set the entrypoints for the checkout extension, and then export them so they can be referenced in your configuration.
For each target that you want to use, create <If extension="react"> a `reactExtension`</If> <If extension="javascript">an `extension`</If> function that references your target, and export it using the default export.
---
This example code uses the `purchase.checkout.contact.render-after` target to render the extension after the contact form element.
You can define more than one static target so that app users can add the extension to multiple locations in the checkout. You can do this by using multiple <If extension="react">`reactExtension`</If><If extension="javascript">`extension`</If> functions with different [static targets](/docs/api/checkout-ui-extensions/latest/extension-targets-overview#static-extension-targets).
<If extension="react">
<Resources>
[reactExtension](/docs/api/checkout-ui-extensions#extension-targets)
[purchase.checkout.contact.render-after](/docs/api/checkout-ui-extensions/latest/targets/information/purchase-checkout-contact-render-after)
</Resources>
</If>
<If extension="javascript">
<Resources>
[extension](/docs/api/checkout-ui-extensions#extension-targets)
[purchase.checkout.contact.render-after](/docs/api/checkout-ui-extensions/latest/targets/information/purchase-checkout-contact-render-after)
</Resources>
</If>
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/shopify.extension.toml" tag="client-validation.extension-point-config"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/shopify.extension.toml" tag="client-validation.extension-point-config"/>
<CheckoutUiReference />
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/shopify.extension.toml" tag="client-validation.capabilities"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/shopify.extension.toml" tag="client-validation.capabilities"/>
#### Configure the `block_progress` capability
In your checkout UI extension's configuration file, for each of your targets, create an `[extensions.capabilities]` section with `block_progress` set to `true`.
---
The `block_progress` capability enables the extension to block checkout progress if the app user allows it when configuring the extension within the [checkout editor](https://help.shopify.com/manual/checkout-settings/checkout-extensibility/checkout-apps).
<Resources>
[block_progress](/docs/api/checkout-ui-extensions/latest/configuration#block-progress)
</Resources>
</Substep>
</Step>
<Step>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" />
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" />
### Check for the ability to block checkout progress
The `block_progress` capability allows extensions to block a customer's progress through checkout.
Adding the `block_progress` capability to your `shopify.extension.toml` file doesn't guarantee that the extension can block checkout progress. The user can allow or disallow this capability in the [checkout editor](https://help.shopify.com/manual/checkout-settings/checkout-extensibility/checkout-apps).
Your extension should update its functionality based on whether the user has allowed the extension to block checkout progress.
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.subscribe-block-progress" />
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.subscribe-block-progress" />
#### Subscribe to `block_progress` capabilities
<If extension="react">
Use the `useExtensionCapability` hook to subscribe to the `block_progress` capability. This hook returns a Boolean value that indicates whether the app user has allowed the extension to block checkout progress.
---
<Resources>
[useExtensionCapability](/docs/api/checkout-ui-extensions/unstable/react-hooks/metadata/useextensioncapability)
[block_progress](/docs/api/checkout-ui-extensions/latest/configuration#block-progress)
</Resources>
</If>
<If extension="javascript">
Use the `capabilities` properties of the `extension` to subscribe to the `block_progress` capability.
---
<Resources>
[extension](/docs/api/checkout-ui-extensions/latest/apis/standardapi#properties-propertydetail-extension)
[block_progress](/docs/api/checkout-ui-extensions/latest/configuration#block-progress)
</Resources>
</If>
</Substep>
</Step>
<Step>
### Render the custom field
Render a text field where the customer can enter their age.
<Substep>
#### Add a text field
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.render-extension"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.render-extension"/>
Use the `TextField` component to create a new field.
---
<Resources>
[TextField](/docs/api/checkout-ui-extensions/latest/components/forms/textfield)
</Resources>
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.field-required"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.field-required"/>
#### Update the text field based on the block progress setting
<If extension="react">
Depending on the value of the `canBlockProgress` variable that's returned from the `useExtensionCapability` hook, set the `required` attribute for the `TextField` component.
</If>
<If extension="javascript">
Use the `canBlockProgress` variable that's returned by querying the `capabilities` properties of the `extension` to set the `required` and `label` properties of the text field.
</If>
In the Shopify checkout, if a field is marked as required, then the customer must fill out the field before they can continue through the checkout.
---
You should adjust your extension UI to handle cases where the user doesn't allow the extension to block the checkout progress, including adjusting the UI accordingly. In this example, the label of the `TextField` updates to indicate if the field is required.
<If extension="react">
<Resources>
[useExtensionCapability](/docs/api/checkout-ui-extensions/current/react-hooks/metadata/useextensioncapability)
[TextField](/docs/api/checkout-ui-extensions/latest/components/forms/textfield)
</Resources>
</If>
<If extension="javascript">
<Resources>
[extension](/docs/api/checkout-ui-extensions/latest/apis/standardapi#properties-propertydetail-extension)
[TextField](/docs/api/checkout-ui-extensions/latest/components/forms/textfield)
</Resources>
</If>
</Substep>
</Step>
<Step>
### Perform validation
Use the `buyerJourney` intercept to show an error message in the checkout UI and block checkout progress when the customer inputs an invalid age.
<Substep>
#### Add the buyerJourney intercept
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.buyer-journey-intercept"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.buyer-journey-intercept"/>
Use the `buyerJourney` intercept to conditionally block checkout progress and update errors in the checkout UI.
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.block-progress"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.block-progress"/>
#### Block the checkout progress
When the customer's age isn't set, or is less than the target age, block the checkout progress by returning an object with a `key` of `behavior` and a value of `block`.
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.field-validation-error"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.field-validation-error"/>
#### Update field validation errors
When the customer's age isn't set, update the field validation errors by setting the `perform` property to a function that updates the field error message.
---
This callback is called when all interceptors finish. You should set errors or reasons for blocking at this stage so that all the errors in the UI show up at the same time.
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.checkout-validation-error"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.checkout-validation-error"/>
#### Add checkout errors
When the customer's age is less than the target age, add an error message by setting the `errors` field of the object returned by the `buyerJourney` intercept. This error is rendered outside of the extension UI.
</Substep>
<Substep>
<CodeRef
extension="react"
href="https://github.com/Shopify/example-checkout--client-validation--react/blob/main/extensions/client-validation/src/Checkout.jsx" tag="client-validation.allow-progress"/>
<CodeRef
extension="javascript"
href="https://github.com/Shopify/example-checkout--client-validation--js/blob/main/extensions/client-validation/src/Checkout.js" tag="client-validation.allow-progress"/>
#### Allow the checkout to continue
When the customer's age is greater than the target age, allow the checkout progress by returning an object with a key of `behavior` and a value of `allow`.
</Substep>
</Step>
<Step>
<CheckoutUiPreview extension="client validation "/>
<Substep>
#### Test the extension functionality
Test your extension to make sure that the custom field validation works as expected.
1. In the checkout, navigate to the **Contact** page.
1. In the **Your age** field, enter a value that's less than the target age (18).
An error is returned and you aren't able to proceed to the next page of the checkout.
---
If you're running an extension locally, then you're automatically granted the `block_progress` capability as long as it's set in your `shopify.extension.toml` file.
To simulate a case where the app user hasn't granted the capability to block checkout progress, you can set the capability to `false` in your `shopify.extension.toml` file, and then restart the extension server.
<CheckoutUiTroubleshooting />
</Substep>
</Step>
<Deploy />
</StepSection>
<NextSteps>
## 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
<CardGrid>
<LinkCard href="/docs/apps/checkout/localizing-ui-extensions">
#### Localize your extension
Learn how to localize the text and number formats in your extension.
</LinkCard>
<LinkCard href="/docs/api/checkout-ui-extensions/latest/components">
#### Explore the checkout UI extension component reference
Learn about all of the components that you can use in your checkout UI extension.
</LinkCard>
<LinkCard href="/docs/api/checkout-ui-extensions/latest/apis/extensiontargets">
#### Explore the checkout UI extension targets API reference
Learn about the extension targets offered in the checkout.
</LinkCard>
</CardGrid>
</NextSteps>