checkout exists only on checkout pages. Guard shared templates with <template-if data-condition="checkout"> when using checkout.*.Order summary: single-product vs cart
Checkout can show either a single-product block (one product, hero image + title) or a cart block (list of items with thumbnails and qty). Use the scope flags to choose.ef-* attributes from the Data Attributes section (right sidebar) when a component is selected.
Subscription products
On single-product checkout pages,checkout.is_subscription and checkout.subscription are set server-side and available immediately when the page loads — no async fetch required.
Intro-offer copy, for example:
template-if to show subscription-specific UI only when the product is a subscription:
item.is_subscription and item.subscription. See Cart — Subscription details.
Totals (display + raw)
Checkout exposes the same totals keys in both modes (is_single_product and is_cart) so one layout can be reused for either flow.
Use formatted keys for display ([[ checkout.total ]]). Use *_raw only for conditions/math.
Recommended template bindings:
- Subtotal row:
[[ checkout.subtotal_after_discount ]] - Total row:
[[ checkout.total ]] - Conditions:
checkout.bump_total_raw > 0,checkout.tax_raw > 0,checkout.shipping_raw > 0
Form fields and validation
Binding fields
Usedata-template-value="checkout.customer.<field>" on each input/select. Paths follow the checkout field spec (e.g. checkout.customer.email, checkout.customer.shipping_first_name).
- Wrap each field in a container (e.g.
.floating-label-group). - Add
<div class="form-error" data-checkout-error="<id>"></div>so the form errors adapter can show validation messages. - Use
checkout.countriesandcheckout.usStatesfor select options (each{ value, label }).
Enforce country/state restrictions server-side
Use backend code to enforce checkout country/state restrictions on submit. Setcheckout_settings in <script scope="backend"> with setVariable(...):
- Restricts the rendered
checkout.countries/checkout.usStateslists. - Enforces the same allowlist in
process-checkout(invalid country/state returns validation errors).
Shipping same as billing
- Bind the checkbox with
data-template-value="checkout.shipping_same_as_billing". - Wrap the shipping address block in
<template-if data-condition="!checkout.shipping_same_as_billing">. - Use
<template-else>to show a short message when shipping equals billing.
Billing section visibility
The entire billing info section can be wrapped in<template-if data-condition="checkout.shipping_same_as_billing == false"> so the billing block is hidden when “same as billing” is checked. Inside that section, use <template-if data-condition="!checkout.shipping_same_as_billing"> for the visible billing form and <template-else> for a short message plus hidden billing inputs so the backend still receives billing data.
Validation errors
errorsis an object keyed by field id:errors['email'],errors['shipping_city'], etc.- The form errors adapter looks for
[data-checkout-error="<id>"]and sets the message; it also adds.errorto the input and.has-errorto the wrapper. - You can show the message in the template:
[[ errors[f.id] ]]ordata-ef-text="errors['email']".
Coupon
- Apply button:
data-apply-coupon(plugin binds to validate + refresh). - Clear button:
data-clear-coupon; show whencheckout.coupon.applied. - Error block:
<template-if data-condition="checkout.coupon_message">with[[ checkout.coupon_message ]].
Order bumps
- Display
[[ bump.price ]]and[[ line.price ]]as-is (already formatted). - Checkbox pattern: Use
data-bump-code,data-bump-checkbox,data-bump-toggleandname="bump",value="[[ bump.code ]]"so the bump plugin can toggle and style. See Cart for the full offer vs added pattern. - Button + @click pattern: Alternatively, use
<button @click="bump.added = true">…</button>for “Add to order” and<button @click="bump.added = false">…</button>for “Remove”. Mutatingbump.addedtriggers re-render. Both checkbox + data-bump-* and button + @click are valid.
Payment panel
Pattern A (generic): Replace the payment block with only:<div class="checkout-cc-panel" data-gateway="nmi"> (or other gateway). Inside: (1) optional cardholder name in <template-if data-condition="!(checkout && checkout.customer && checkout.customer.first_name)"> with data-template-value="checkout.customer.cardholder_name" and <div class="form-error" id="cc-name-error"></div>; (2) a secure-card-element div with data-brand-id, data-domain-id, data-merchant-code, data-accepted-cards, plus a sibling <div class="form-error" id="nmi-card-errors"></div> for card errors.
Smart field detection
The payment panel usesisFieldOnPage() to check whether specific checkout fields are present on the page. Based on what’s missing, it automatically adds fields inside the card section:
- No
first_name/last_nameon page → shows “Cardholder Name” input - No
billing_address/shipping_addresson page → shows billing details (name, country, address)
isFieldOnPage() in your own template-if conditions:
data-template-value, data-ef-value, or name attribute. Elements inside the payment panel itself are excluded to prevent self-referencing.
Wallet (Apple Pay / Google Pay)
Scope key
Use in template conditions to show wallet-specific content:
Wallet-first layout
Wallet buttons are rendered inside<checkout-cc-panel>. To make them prominent (e.g. for quiz funnels), place the payment panel above the shipping address section in your template. Both layouts use the same blocks and backend processing.
ef.checkout API
For programmatic wallet control, a small JavaScript API is available on window.ef.checkout:
ef.checkout.walletAvailable— same data ascheckout.wallet_availablescope keyef.checkout.payWithWallet(method)— triggers'applePay'or'googlePay'programmaticallyef.checkout.onWalletComplete(callback)— fires after wallet payment attempt
window.ef.checkout API.
Summary
- Use
is_single_product/is_cartandcheckout.product_*vs cartItems for order summary. - Subscriptions:
checkout.is_subscription+checkout.subscriptionon single-product pages (server-side, available immediately);item.is_subscription+item.subscriptionon cart items. - Prefer explicit subtotal keys:
checkout.subtotal_before_discount/checkout.subtotal_after_discount. checkout.subtotalremains as a backward-compatible alias ofcheckout.subtotal_after_discount.- Use
_rawkeys only for conditions/math or explicit formatting withformatPrice. - Bind fields with data-template-value, use data-checkout-error and errors for validation.
- Coupon: query.coupon, checkout.coupon, checkout.coupon_message; data-apply-coupon, data-clear-coupon.
- Bumps: checkout.bump_products, checkout.selectedBumpLines; data-bump-* attributes.
- Payment: Pattern A —
<checkout-cc-panel></checkout-cc-panel>only; Pattern B — explicit gateway div withdata-gateway, optional cardholder, secure-card-element. - Wallet:
checkout.wallet_visible(orcheckout.wallet_available) for conditional content;ef.checkout.payWithWallet()for programmatic triggers; use<checkout-wallet force="true" />above the form for wallet-first layouts.