PlaceOrder container
The PlaceOrder container handles the final step in the checkout process, where the user confirms and places an order. Configure it to disable the button, perform validations before submitting the form, handle the place order action, and manage the content slot for the place order button.
PlaceOrder configurations
The PlaceOrder container provides the following configuration options:
These configuration options implement the PlaceOrderProps interface:
PlaceOrderProps interface
The PlaceOrder container receives an object that implements the PlaceOrderProps interface:
export interface PlaceOrderProps extends HTMLAttributes<HTMLDivElement> { active?: boolean; disabled?: boolean; handleValidation?: () => boolean | Promise<boolean>; handlePlaceOrder: (ctx: HandlePlaceOrderContext) => Promise<void>; slots?: { Content?: SlotProps<ContentSlotContext>; };}-
The
activeproperty controls whether the container responds to system events and renders. Set to true (default) for reactive mode. Set to false to deactivate and hide the container. -
The
disabledproperty forces the Place Order button into a disabled state when set to true. -
The
handleValidationproperty performs validation checks before submitting the checkout forms and placing the order. It returns abooleansynchronously or aPromise<boolean>for asynchronous validation (for example, server-side fraud checks). -
The
handlePlaceOrderproperty executes when the user clicks the Place Order button andhandleValidationreturns true (when provided). It accepts a context parameter that implements theHandlePlaceOrderContextinterface:export interface HandlePlaceOrderContext {code: string;cartId: string;} -
The
slotsproperty contains the following:- The
Contentslot renders PlaceOrder container content based on the selected payment method code:
export type SlotProps<T = any> = (ctx: T & DefaultSlotContext<T>,element: HTMLDivElement | null) => Promise<void> | void;export interface ContentSlotContext {code: string;} - The
Example 1: Render performing validations and a handler for order placement
The following example renders the PlaceOrder container on a checkout page using the PaymentServices drop-in component as a payment method. It includes functionality to validate login, shipping, billing, and terms & conditions forms before placing an order. If the validation passes, it attempts to place the order and handles any errors.
// Checkout Dropinimport PlaceOrder from '@dropins/storefront-checkout/containers/PlaceOrder.js';import { render as CheckoutProvider } from '@dropins/storefront-checkout/render.js';
// Order Dropin Modulesimport * as orderApi from '@dropins/storefront-order/api.js';
// Payment Services Dropinimport { PaymentMethodCode } from '@dropins/storefront-payment-services/api.js';
import { scrollToElement } from '../../scripts/checkout.js';
const LOGIN_FORM_NAME = 'login-form';const SHIPPING_FORM_NAME = 'selectedShippingAddress';const BILLING_FORM_NAME = 'selectedBillingAddress';const TERMS_AND_CONDITIONS_FORM_NAME = 'checkout-terms-and-conditions__form';
const $placeOrder = checkoutFragment.querySelector('.checkout__place-order');
const shippingFormRef = { current: null };const billingFormRef = { current: null };const creditCardFormRef = { current: null };
CheckoutProvider.render(PlaceOrder, { handleValidation: () => { let success = true; const { forms } = document;
const loginForm = forms[LOGIN_FORM_NAME];
if (loginForm) { success = loginForm.checkValidity(); if (!success) scrollToElement($login); }
const shippingForm = forms[SHIPPING_FORM_NAME];
if ( success && shippingFormRef.current && shippingForm && shippingForm.checkVisibility() ) { success = shippingFormRef.current.handleValidationSubmit(false); }
const billingForm = forms[BILLING_FORM_NAME];
if ( success && billingFormRef.current && billingForm && billingForm.checkVisibility() ) { success = billingFormRef.current.handleValidationSubmit(false); }
const termsAndConditionsForm = forms[TERMS_AND_CONDITIONS_FORM_NAME];
if (success && termsAndConditionsForm) { success = termsAndConditionsForm.checkValidity(); if (!success) scrollToElement($termsAndConditions); }
return success; }, handlePlaceOrder: async ({ cartId, code }) => { await displayOverlaySpinner(); 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(); } // Place order await orderApi.placeOrder(cartId); } catch (error) { console.error(error); throw error; } finally { removeOverlaySpinner(); } },})($placeOrder),Example 2: Render providing explicit content for the button
The following example renders the PlaceOrder container on a checkout page providing different text for the Place Order button depending on the selected payment method.
// Checkout Dropinimport PlaceOrder from '@dropins/storefront-checkout/containers/PlaceOrder.js';import { render as CheckoutProvider } from '@dropins/storefront-checkout/render.js';
// Order Dropin Modulesimport * as orderApi from '@dropins/storefront-order/api.js';
const $placeOrder = checkoutFragment.querySelector('.checkout__place-order');
CheckoutProvider.render(PlaceOrder, { handlePlaceOrder: async ({ cartId }) => { orderApi.placeOrder(cartId).catch(console.error); }, slots: { Content: (ctx) => { const content = document.createElement('span'); ctx.appendChild(content);
function setContent(currentCtx) { switch (currentCtx.code) { case 'checkmo': { content.textContent = 'Pay Now'; break; } case 'banktransfer': { content.textContent = 'Make a transfer'; break; } default: { content.textContent = currentCtx.dictionary.Checkout.PlaceOrder.button; } } }
setContent(ctx); ctx.onChange(setContent); }, },})($placeOrder),