Skip to content
Tutorials

Validate a shipping address

When your address verification service returns a suggested shipping address that differs from what a shopper entered, you can let them choose between the two before placing the order. This tutorial shows you how to add that confirmation step to the commerce-checkout block using the AddressValidation container.

  • Edit the checkout block — blocks/commerce-checkout/commerce-checkout.js
  • Edit the AddressValidation container
  • Edit the PlaceOrder container
  • Create the validation stub — blocks/commerce-checkout/utils.js

By the end of this tutorial, you’ll have:

  • A modal that renders the AddressValidation container, showing the shopper’s original and suggested shipping addresses.
  • Address verification wired into the handlePlaceOrder callback of the PlaceOrder container, running before the order places.
  • The shipping form updated automatically when the shopper selects the suggested address.

Validate shipping address

AddressValidation displayed in a modal
// in commerce-checkout.js block
import * as checkoutApi from '/@dropins/storefront-checkout/api.js';
import * as orderApi from '/@dropins/storefront-order/api.js';
import { PaymentMethodCode } from '/@dropins/storefront-payment-services/api.js';
import { events } from '@adobe-commerce/event-bus';
import { SHIPPING_ADDRESS_DATA_KEY } from '/constants.js';
import { showModal, validateAddress } from '/utils.js';
// Handler passed to the PlaceOrder container
const handlePlaceOrder = async ({ cartId, code }) => {
await displayOverlaySpinner(loaderRef, $loader);
try {
// Payment Services credit card
if (code === PaymentMethodCode.CREDIT_CARD) {
if (!creditCardFormRef.current) {
console.error('Credit card form not rendered.');
return;
}
if (!creditCardFormRef.current.validate()) {
// Credit card form invalid; abort order placement
return;
}
// Submit Payment Services credit card form
await creditCardFormRef.current.submit();
}
// Address validation
const suggestion = await validateAddress();
if (suggestion) {
const container = document.createElement('div');
await showModal(container);
await renderAddressValidation(container, {
suggestedAddress: suggestion,
handleSelectedAddress: async ({ selection, address }) => {
if (selection === 'suggested') {
// Update the shipping form using the suggested address
sessionStorage.removeItem(SHIPPING_ADDRESS_DATA_KEY);
shippingForm.setProps((prevProps) => ({
...prevProps,
inputsDefaultValueSet: address,
}));
} else {
// Place order
await orderApi.placeOrder(cartId);
}
removeModal();
},
});
} else {
// Place order
await orderApi.placeOrder(cartId);
}
} catch (error) {
console.error(error);
throw error;
} finally {
removeOverlaySpinner(loaderRef, $loader);
}
};
// in containers.js
import AddressValidation from '/@dropins/storefront-checkout/containers/AddressValidation.js';
import { render as CheckoutProvider } from '/@dropins/storefront-checkout/render.js';
/**
* Renders the AddressValidation container in its own host element
* @param {HTMLElement} container - DOM element to render into
*/
export const renderAddressValidation = async (
container,
{ suggestedAddress, handleSelectedAddress }
) =>
CheckoutProvider.render(AddressValidation, {
suggestedAddress,
handleSelectedAddress,
})(container);
// in utils.js (example stub)
export const validateAddress = async () => {
// Here’s where your API call goes
return {
city: 'Bainbridge Island',
countryCode: 'US',
postcode: '98110-2450',
region: 'CA',
street: ['123 Winslow Way E'],
};
};

Finally, add some padding for better appearance:

commerce-checkout.css
.modal-content .checkout-address-validation {
padding: var(--spacing-big);
}