Skip to content
Tutorials

Buy online, pickup in store

Buy online, pickup in store (BOPIS) lets shoppers buy items on your storefront and pick them up in person. The Commerce boilerplate doesn’t include a BOPIS checkout flow by default, but this tutorial shows you how to add one with Adobe’s drop-in components.

  • Edit the checkout block — blocks/commerce-checkout/commerce-checkout.js
  • Edit the ToggleButton component
  • Edit the RadioButton component
  • Create the fetchPickupLocations() function

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

  • Delivery and in-store pickup toggle buttons added to the commerce-checkout.js block file using the ToggleButton component.
  • A list of pickup locations fetched from Adobe Commerce and rendered as RadioButton options.
  • The shipping address updated with the selected pickup location code when a shopper chooses in-store pickup.

The following steps describe how to modify the commerce-checkout.js block file in the boilerplate template to allow users to choose between delivery and in-store pickup during the checkout process.

Before you start, you must configure in-store delivery options in the Adobe Commerce Admin to define pickup locations. The fetchPickupLocations function retrieves the list of available pickup locations using a GraphQL query.

  1. To create a new section for the delivery options, additional DOM elements are required. You can add these elements by modifying the content fragment.

    <div class="checkout__block checkout__delivery-method">
    <h2 class="checkout__block checkout-delivery-method__title">Delivery Method</h2>
    <div class="checkout__block checkout-delivery-method__toggle-buttons">
    <div class="checkout__block checkout-delivery-method__delivery-button"></div>
    <div class="checkout__block checkout-delivery-method__in-store-pickup-button"></div>
    </div>
    </div>
    <div class="checkout__block checkout__in-store-pickup"></div>
  2. You must also add new selectors to render the required components and content.

    const $deliveryButton = checkoutFragment.querySelector('.checkout-delivery-method__delivery-button');
    const $inStorePickupButton = checkoutFragment.querySelector('. checkout-delivery-method__in-store-pickup-button');
    const $inStorePickup = checkoutFragment.querySelector('.checkout__in-store-pickup');

    Update content fragment

During initialization, the code renders two buttons:

  • Delivery
  • In-store pickup

These buttons allow users to toggle between the two options.

UI.render(ToggleButton, {
label: 'Delivery',
onChange: () => onToggle('delivery'),
})($deliveryButton),
UI.render(ToggleButton, {
label: 'In-store Pickup',
onChange: () => onToggle('in-store-pickup'),
})($inStorePickupButton),

Toggle buttons

The onToggle function manages switching between the delivery and in-store pickup options. It updates the selected state of the buttons and toggles the visibility of the corresponding forms.

async function onToggle(type) {
if (type === 'delivery') {
deliveryButton.setProps((prev) => ({ ...prev, selected: true }));
inStorePickupButton.setProps((prev) => ({ ...prev, selected: false }));
$shippingForm.removeAttribute('hidden');
$delivery.removeAttribute('hidden');
$inStorePickup.setAttribute('hidden', '');
} else {
inStorePickupButton.setProps((prev) => ({ ...prev, selected: true }));
deliveryButton.setProps((prev) => ({ ...prev, selected: false }));
$shippingForm.setAttribute('hidden', '');
$delivery.setAttribute('hidden', '');
$inStorePickup.removeAttribute('hidden');
}
}

The fetchPickupLocations function retrieves the list of available pickup locations using a GraphQL query. Users can choose a location where they’d like to pick up their order.

async function fetchPickupLocations() {
return checkoutApi
.fetchGraphQl(
`query pickupLocations {
pickupLocations {
items {
name
pickup_location_code
}
total_count
}
}`,
{ method: 'GET', cache: 'no-cache' }
)
.then((res) => res.data.pickupLocations.items);
}

After the code fetches the pickup locations, it renders options as radio buttons. The user can select a location, which updates the shipping address with the corresponding pickup location code.

const pickupLocations = await fetchPickupLocations();
pickupLocations.forEach((location) => {
const { name, pickup_location_code } = location;
const locationRadiobutton = document.createElement('div');
UI.render(RadioButton, {
label: name,
name: 'pickup-location',
value: name,
onChange: () => {
checkoutApi.setShippingAddress({
address: {},
pickupLocationCode: pickup_location_code,
});
},
})(locationRadiobutton);
$inStorePickup.appendChild(locationRadiobutton);
});

Pick up location options

After a user selects In-store pickup and chooses a location, the pickup form is shown, while the shipping form is hidden. This provides a clear and seamless way for users to choose how they want to receive their order.