Validate address in My Account
Use the AddressValidation
container to present both the original and suggested addresses from your verification service, letting shoppers choose before saving. This tutorial shows how to integrate the container in the commerce-addresses
block.
AddressValidation displayed in a modal
Overview
At a high level:
- Call your address verification service on form submit.
- If it returns a suggestion, open a modal and render
AddressValidation
. - If the shopper selects the suggestion, populate the form with the suggested data and re-submit; otherwise, retain the original form values.
Integration in commerce-addresses block
Update your blocks/commerce-addresses/commerce-addresses.js
to:
- Import
AddressValidation
- Pass
forwardFormRef
,onAddressData
, andonSubmit
toAddresses
- When a suggestion exists, show a modal with
AddressValidation
and two actions: Edit Address and Save Address
// blocks/commerce-addresses/commerce-addresses.jsimport { Addresses } from '@dropins/storefront-account/containers/Addresses.js';import AddressValidation from '@dropins/storefront-account/containers/AddressValidation.js';import { render as accountRenderer } from '@dropins/storefront-account/render.js';import { Button, provider as UI } from '@dropins/tools/components.js';import { readBlockConfig } from '../../scripts/aem.js';import { CUSTOMER_ADDRESS_PATH, CUSTOMER_LOGIN_PATH, checkIsAuthenticated, rootLink,} from '../../scripts/commerce.js';import { showModal, removeModal } from './modal-utils.js';
const validateAddress = async (address) => { // Call your service with the form data // const result = await fetch(...) // return result.suggestedAddress || null
// Example mocked suggestion return { city: 'Bainbridge Island', countryCode: 'US', postcode: '98110-2450', region: { regionCode: 'WA', regionId: 1 }, street: ['123 Winslow Way E'], telephone: '555-123-4567', };};
const finalizeSubmission = (setContainerProps, formRef, updates = {}) => { setContainerProps({ onSubmit: null, ...updates }); setTimeout(() => formRef.current?.requestSubmit(), 1);};
const renderAddressValidation = async ({ originalAddress, suggestedAddress, onEdit, onSave,}) => { const container = document.createElement('div'); const addressValidation = document.createElement('div'); const actionsContainer = document.createElement('div'); const editAddressButton = document.createElement('div'); const saveAddressButton = document.createElement('div'); actionsContainer.appendChild(editAddressButton); actionsContainer.appendChild(saveAddressButton); container.appendChild(addressValidation); container.appendChild(actionsContainer); actionsContainer.classList.add('actions-container');
await showModal(container);
let selectedAddress, currentSelection; provider.render(AddressValidation, { selectedAddress: 'suggested', originalAddress, suggestedAddress, handleSelectedAddress: async ({ address, selection }) => { selectedAddress = address; currentSelection = selection; }, })(addressValidation);
UI.render(Button, { children: 'Edit Address', size: 'medium', variant: 'secondary', onClick: () => { if (currentSelection === 'suggested') { onEdit(selectedAddress); } removeModal(); }, })(editAddressButton);
UI.render(Button, { children: 'Save Address', size: 'medium', variant: 'primary', onClick: () => { const updates = {}; if (currentSelection === 'suggested') { updates.inputsDefaultValueSet = selectedAddress; } removeModal(); onSave(updates); }, })(saveAddressButton);};
export default async function decorate(block) { const { 'minified-view': minifiedViewConfig = 'false' } = readBlockConfig(block);
if (!checkIsAuthenticated()) { window.location.href = rootLink(CUSTOMER_LOGIN_PATH); return; }
let originalAddress; const formRef = { current: null };
const addressesContainer = await accountRenderer.render(Addresses, { minifiedView: minifiedViewConfig === 'true', withActionsInMinifiedView: false, withActionsInFullSizeView: true, routeAddressesPage: () => rootLink(CUSTOMER_ADDRESS_PATH), forwardFormRef: formRef, onAddressData: (values) => { originalAddress = values?.data; }, onSubmit: async (event, formValid) => { if (!formValid) return;
const setContainerProps = (updates) => { addressesContainer.setProps((prev) => ({ ...prev, ...updates })); };
const suggestedAddress = await validateAddress(originalAddress); if (!suggestedAddress) { finalizeSubmission(setContainerProps, formRef); return; }
await renderAddressValidation({ originalAddress, suggestedAddress, onEdit: (selectedAddress) => { setContainerProps({ inputsDefaultValueSet: selectedAddress }); }, onSave: (updates) => { finalizeSubmission(setContainerProps, formRef, updates); }, }); }, })(block);}
// modal-utils.jsimport createModal from '../modal/modal.js';
let modal;
export const showModal = async (content) => { modal = await createModal([content]); modal.showModal();};
export const removeModal = () => { if (!modal) return; modal.removeModal(); modal = null;};
Optional styles
/* Minimal layout for the modal */.modal-content { padding: 32px;}
.actions-container { display: flex; gap: 16px; margin-top: 48px; justify-content: flex-end;}
Next steps
- See the
AddressValidation
container container for props and behaviors. - Ensure your suggestion matches the
CustomerAddressInput
shape expected by the Addresses container.