feature-cart hooks
The components already use these hooks. Reach for them when you build your own UI on the same data. Open a hook for its options and what it returns.
Reading data
useAvailablePaymentMethodsThe payment methods on offer for a cart.
import { useAvailablePaymentMethods } from "@evolve-storefront/feature-cart/hooks";device is required by the schema and changes the answer, so it is an argument
rather than a default — a wallet method is offered on a phone and not on a
desktop, and picking "WEB" silently for a native shell would hide methods that
shell can actually take.
function useAvailablePaymentMethods(cartId: string | undefined, device: ClientDevice)Returns A React Query result: data, isPending, error and the rest.
useAvailableShippingMethodsThe delivery methods on offer for a cart (–D3).
import { useAvailableShippingMethods } from "@evolve-storefront/feature-cart/hooks";Gated on cartId as well as the session: there is nothing to offer methods for
until a cart exists, and a query that fires without one asks the backend a
question with no subject.
function useAvailableShippingMethods(cartId: string | undefined)Returns A React Query result: data, isPending, error and the rest.
useCartThe active cart.
import { useCart } from "@evolve-storefront/feature-cart/hooks";Auth-gated, so it reports isPending (never isLoading) until the session is
established. Render the skeleton while isPending; isSuccess && !data is an
empty cart, which is a state to render, not a 404.
function useCart()Returns A React Query result: data, isPending, error and the rest.
useCartApprovalRequirementWhether placing the current cart now would wait for approval, and on whom, for CartApprovalNotice.
import { useCartApprovalRequirement } from "@evolve-storefront/feature-cart/hooks";function useCartApprovalRequirement()Returns A React Query result: data, isPending, error and the rest.
useCartChangesWhat changed in the current cart since the buyer last looked (sold-out lines, price changes, lowered quantities) and the lines that cannot be ordered now, for CartChangesNotice, the line marks and CartUnavailableLines.
import { useCartChanges } from "@evolve-storefront/feature-cart/hooks";function useCartChanges()Returns A React Query result: data, isPending, error and the rest.
useCartComplementaryProductsProducts to suggest alongside the current cart, at most three, for CartCrossSell.
import { useCartComplementaryProducts } from "@evolve-storefront/feature-cart/hooks";function useCartComplementaryProducts(options?: { limit?: number | undefined; })| Option | Type | Description |
|---|---|---|
limit? | number |
Returns A React Query result: data, isPending, error and the rest.
useCartDeliveryPromiseWhen the current cart arrives, for CartDeliveryUsps: at the cart's shipping address, or at country until it has one.
import { useCartDeliveryPromise } from "@evolve-storefront/feature-cart/hooks";function useCartDeliveryPromise(options: { country?: string | undefined; enabled?: boolean | undefined; })| Option | Type | Description |
|---|---|---|
country? | string | Where to promise delivery before the cart has a shipping address, such as the store's country. |
enabled? | boolean |
Returns A React Query result: data, isPending, error and the rest.
useCartMinimumOrderHow far the current cart is from its business unit's minimum order value, for CartMinimumOrderNotice and the order button's blockedReason.
import { useCartMinimumOrder } from "@evolve-storefront/feature-cart/hooks";function useCartMinimumOrder()Returns A React Query result: data, isPending, error and the rest.
useCartsOne page of the business unit's carts.
import { useCarts } from "@evolve-storefront/feature-cart/hooks";Disabled entirely in single-cart mode — config, not a fork — and disabled without
a businessUnitId too, because carts hangs off BusinessUnit: a personal
session has no carts list to read.
data is a page ({ items, pagination }), not an array. A caller rendering only
the first page has to say so; see CartSwitcher.
function useCarts(options?: UseCartsOptions)| Option | Type | Description |
|---|---|---|
page? | number | 1-based. Defaults to the first page. |
pageSize? | number | Defaults to the server's 20. |
Returns A React Query result: data, isPending, error and the rest.
useDeliveryDatesThe delivery dates for a cart.
import { useDeliveryDates } from "@evolve-storefront/feature-cart/hooks";function useDeliveryDates(cartId: string | undefined, options?: { enabled?: boolean | undefined; days?: number | undefined; from?: string | undefined; })| Option | Type | Description |
|---|---|---|
enabled? | boolean | |
days? | number | |
from? | string |
Returns A React Query result: data, isPending, error and the rest.
useDeliveryPreferenceComplete or split, the requested date, and the backordered lines of a cart.
import { useDeliveryPreference } from "@evolve-storefront/feature-cart/hooks";function useDeliveryPreference(cartId: string | undefined, options?: { enabled?: boolean | undefined; })| Option | Type | Description |
|---|---|---|
enabled? | boolean |
Returns A React Query result: data, isPending, error and the rest.
usePickupPointsThe pickup points for a cart: near near, or near the shipping address without it.
import { usePickupPoints } from "@evolve-storefront/feature-cart/hooks";function usePickupPoints(cartId: string | undefined, options?: { near?: PickupPointLocation | undefined; enabled?: boolean | undefined; })| Option | Type | Description |
|---|---|---|
near? | PickupPointLocation | |
enabled? | boolean |
Returns A React Query result: data, isPending, error and the rest.
useShippingEstimatesThe carrier and delivery estimate of each method on offer for a cart.
import { useShippingEstimates } from "@evolve-storefront/feature-cart/hooks";function useShippingEstimates(cartId: string | undefined, options?: { enabled?: boolean | undefined; })| Option | Type | Description |
|---|---|---|
enabled? | boolean |
Returns A React Query result: data, isPending, error and the rest.
useVatNumberCheckThe register's answer for a VAT number, once it is long enough to ask about.
import { useVatNumberCheck } from "@evolve-storefront/feature-cart/hooks";function useVatNumberCheck(vatNumber: string, options?: { country?: string | undefined; enabled?: boolean | undefined; })| Option | Type | Description |
|---|---|---|
country? | string | |
enabled? | boolean |
Returns A React Query result: data, isPending, error and the rest.
Changing data
useAddBundleToCartAdd a product and its chosen extras as one bundle, such as "complete the look".
import { useAddBundleToCart } from "@evolve-storefront/feature-cart/hooks";function useAddBundleToCart(options?: UseAddToCartOptions)| Option | Type | Description |
|---|---|---|
onAdded? | ((result: LineItemsAddedResult) => void) | Overrides |
silent? | boolean | This add is a side effect of another interaction, not a shopper adding a
product: fire no confirmation and make no announcement, but still report
|
Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useAddDiscountCodeApply and remove discount codes.
import { useAddDiscountCode } from "@evolve-storefront/feature-cart/hooks";Neither is optimistic: a code's validity and its amount are entirely the server's call, so an optimistic apply would show a discount that may not exist.
function useAddDiscountCode()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useAddToCartAdd lines to the active cart, creating one only when there is none.
import { useAddToCart } from "@evolve-storefront/feature-cart/hooks";Resolves the cart id and version itself, from the query the mini-cart already renders,
and awaits it — a click during load would otherwise create a second cart. Always the
active cart; there is no target argument. Opens CartAddedSheet as the add is sent
and fires CartProvider.onLineItemsAdded with the result, unless the call site passes
its own onAdded.
Inside an AddToCartScope, isPending is true while any add in the scope is.
function useAddToCart(options?: UseAddToCartOptions)| Option | Type | Description |
|---|---|---|
onAdded? | ((result: LineItemsAddedResult) => void) | Overrides |
silent? | boolean | This add is a side effect of another interaction, not a shopper adding a
product: fire no confirmation and make no announcement, but still report
|
Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useApplyGiftCardPays part or all of the cart with a card.
import { useApplyGiftCard } from "@evolve-storefront/feature-cart/hooks";function useApplyGiftCard()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useCartMutationShared plumbing for every cart write.
import { useCartMutation } from "@evolve-storefront/feature-cart/hooks";Every mutation returns the cart carrying its new version, so the write
path is uniform: run it, then put the authoritative entity in the cache. No
follow-up read, and no active-vs-non-active branching — an optimistic patch (if
any) is applied by the caller and always replaced by this response.
The session is established here, ahead of the request, because this is the
one place every cart write passes through — see CartContextValue.ensureSession.
The multi-cart management writes in useCartManagement do not, and need not: a
company's carts belong to an associate who is already signed in.
function useCartMutation(args: { document: TypedDocumentNode<Record<Field, Payload>, Variables>; field: Field; mutationKey?: readonly unknown[] | undefined; resolveVariables?: ((variables: Va…)| Option | Type | Description |
|---|---|---|
document | TypedDocumentNode<Record<Field, Payload>, Variables> | |
field | Field | |
mutationKey? | readonly unknown[] | Tags the mutation, so |
resolveVariables? | ((variables: Variables) => Promise<Variables>) | Last chance to complete the variables, run once the session exists and
before the request goes out. |
onStarted? | ((variables: Variables) => void) | Runs as the write is sent, before the session or the cart is resolved. |
onFailed? | ((error: Error) => void) | Runs when the write failed, after the optimistic patch is rolled back. |
onOptimistic? | ((cart: Cart, variables: Variables) => Cart) | Applied before the request, and always superseded by the response. |
retryOnConflict? | ((fresh: Cart, variables: Variables) => Variables | "done" | null) | Try once more after |
onWritten? | ((cart: Cart, variables: Variables, warnings: TypedError[], payload: Payload | null) => void) | Runs after the authoritative cart is in the cache. |
Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useClearCartEmpty the cart.
import { useClearCart } from "@evolve-storefront/feature-cart/hooks";This is the implementation, not a stand-in. cartClear was proposed in
proposed and dropped: removing every line in one
cartLineItemsRemove is a single round trip, and the optional version
covers the concurrency the proposal worried about.
It removes only the lines this client can see, so a line a colleague added between the read and the click survives. That is the accepted cost of not having a server-side clear.
A cleared cart keeps any applied discount code — cartLineItemsRemove
cannot remove one, and that is accepted: the buyer applied it deliberately, it
stays visible in the breakdown, and removing the code is its own action. A
visible state with a way out, not a trap.
function useClearCart()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus clear, warnings.
useCreateCartCreate a cart under a name.
import { useCreateCart } from "@evolve-storefront/feature-cart/hooks";cartCreateNamed is one call rather than create-then-rename-then-switch, and its
name is required — which is why CartCreateDialog asks for one.
function useCreateCart()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useDeleteCartDelete a cart.
import { useDeleteCart } from "@evolve-storefront/feature-cart/hooks";When the deleted cart was the current one the server promotes a successor and says which — so the client refetches what it named rather than choosing one itself. Picking a successor client-side is how two tabs end up on different carts.
null is a legitimate answer, not a failure: the caller has no cart left, which
is the empty state.
function useDeleteCart()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useGiftCardBalanceChecks a card's balance.
import { useGiftCardBalance } from "@evolve-storefront/feature-cart/hooks";function useGiftCardBalance()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
usePayCartPay for the cart, under payment first: pay, then the order is created from the confirmation.
import { usePayCart } from "@evolve-storefront/feature-cart/hooks";target: { type: CART } is required, so paying a cart cannot be confused with paying
an order by omission. Nothing is invalidated: a refetch would race the redirect.
function usePayCart(returnUrls: CheckoutReturnUrls)| Option | Type | Description |
|---|---|---|
successUrl | string | |
cancelUrl | string | |
failureUrl | string |
Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
usePlaceAndPayusePlaceOrder followed by the injected pay, as one mutation: isPending spans both, error is the place's, and the outcome says where to go.
import { usePlaceAndPay } from "@evolve-storefront/feature-cart/hooks";function usePlaceAndPay(options: PlaceAndPayOptions)| Option | Type | Description |
|---|---|---|
pay | CheckoutPay | |
onPlaced? | ((placed: PlaceOrderResult) => void) | Called once the order exists and before paying, which may leave the app — the moment to replace the checkout URL with one that knows about the order. |
Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
usePlaceOrderPlace the order for the cart.
import { usePlaceOrder } from "@evolve-storefront/feature-cart/hooks";It does not pay for it. That is the split: this turns a cart into an order, and
an order is paid through feature-order, which is the one place a payment starts.
A checkout that reaches a payable order routes to it and pays there; a checkout
that reaches an order held for approval routes to it and says so.
The consequence is that orderCreationStrategy stops being something a storefront
reasons about. There is no after-payment branch left to configure, so there is no
pair of failure modes a caller had to tell apart from a response that could not
distinguish them.
Deliberately not a useCartMutation: orderPlace returns no cart, so there is
nothing authoritative to write.
What it does do is drop the cart from the cache once an order exists. An order
means the backend has finished with that cart — it is Ordered and the current-cart
pointer has moved — so serving the cached copy would re-offer a basket that can no
longer be checked out. Only on success now, because a failure leaves the cart
exactly as it was.
function usePlaceOrder()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useRemoveDiscountCodeRemoves an applied discount code.
import { useRemoveDiscountCode } from "@evolve-storefront/feature-cart/hooks";function useRemoveDiscountCode()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useRemoveGiftCardTakes a card off the cart and gives its hold back.
import { useRemoveGiftCard } from "@evolve-storefront/feature-cart/hooks";function useRemoveGiftCard()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useRemoveLineItemRemove lines, and the add-ons linked to them.
import { useRemoveLineItem } from "@evolve-storefront/feature-cart/hooks";function useRemoveLineItem()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useRenameCartRename a cart.
import { useRenameCart } from "@evolve-storefront/feature-cart/hooks";function useRenameCart()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useSetBillingAddressThe billing address.
import { useSetBillingAddress } from "@evolve-storefront/feature-cart/hooks";A company cart's billing address comes from the business unit and is not
editable in checkout, so a B2B composition renders a read-only summary
and never calls this. The hook has no B2B variant because the cart carries no
businessUnit and this package cannot tell — see the README.
function useSetBillingAddress()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useSetCartShippingAddressSet the cart's delivery address, and hand back the id the cart now has.
import { useSetCartShippingAddress } from "@evolve-storefront/feature-cart/hooks";This exists to be injected. feature-quote's request dialog needs the
basket to carry a delivery destination before it can be quoted, but a
feature package never depends on another feature — so the dialog takes a
setShippingAddress seam and a site wires this hook into it:
const setShippingAddress = useSetCartShippingAddress(cart);
<QuoteRequestButton cartId={cart.id} setShippingAddress={setShippingAddress} … />
It returns the new cart id, and that is the whole point of the signature.
cartUpdate issues a fresh composite id on every write (see lib/cart-ref.ts),
so whatever runs next must use the id this resolved with rather than the one
its page rendered with. Returning it makes that a type obligation instead of a
race that passes locally. Now that the id stops changing,
the signature simply stops mattering.
Not optimistic: the server echoes the normalized address back, and a cart showing an address the backend rejected is worse than a moment's wait.
function useSetCartShippingAddress( cart: { id: string; version?: string | undefined; },): (address: CartShippingAddressInput) => Promise<{ cartId: string }>| Option | Type | Description |
|---|---|---|
id | string | |
version? | string |
Returns (address: CartShippingAddressInput) => Promise<{ cartId: string }>
useSetCurrentCartSwitch the current cart.
import { useSetCurrentCart } from "@evolve-storefront/feature-cart/hooks";cartSetCurrent moves the pointer and modifies no cart, so the list needs no
refetch: no entry changed, and no entry carries a current marker to go stale.
What does change is what Query.cart answers, so that one is invalidated —
which also fetches the whole cart the card-shaped response cannot supply.
function useSetCurrentCart()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useSetCustomerEmailThe email the order confirmation goes to.
import { useSetCustomerEmail } from "@evolve-storefront/feature-cart/hooks";function useSetCustomerEmail()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useSetDeliveryPreferenceSet complete or split and the requested date; null drops the date.
import { useSetDeliveryPreference } from "@evolve-storefront/feature-cart/hooks";function useSetDeliveryPreference()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useSetDeliveryRemarksRecord the buyer's note for whoever delivers; null clears it.
import { useSetDeliveryRemarks } from "@evolve-storefront/feature-cart/hooks";The write bumps the cart's version, so a write sent with an older one is refused as a conflict and retried once against the cart as the server has it — the remarks and the reference saved back to back is the common case. Not optimistic: the server echoes the note back, and showing one it rejected is worse than a wait.
function useSetDeliveryRemarks( cart: { id: string; version?: string | undefined; },): { setDeliveryRemarks: (remarks: string | null) => Promise<void>; isPending: boolean; error: unknown;}| Option | Type | Description |
|---|---|---|
id | string | |
version? | string |
Returns { setDeliveryRemarks: (remarks: string | null) => Promise<void>; isPending: boolean; error: unknown; }
useSetDeliverySlotChoose a slot, which also sets its shipping method.
import { useSetDeliverySlot } from "@evolve-storefront/feature-cart/hooks";function useSetDeliverySlot()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useSetPaymentMethodThe payment method.
import { useSetPaymentMethod } from "@evolve-storefront/feature-cart/hooks";Takes internalId + provider rather than the method's id, because that pair
is what identifies a method to its provider and what paymentCreate needs
back.
function useSetPaymentMethod()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useSetPickupPointChoose a pickup point: the cart ships to it and its carrier's method is set.
import { useSetPickupPoint } from "@evolve-storefront/feature-cart/hooks";function useSetPickupPoint()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useSetPurchaseReferenceRecord the buyer's own reference for this purchase, usually a purchase order number.
import { useSetPurchaseReference } from "@evolve-storefront/feature-cart/hooks";Business-unit only. The engine accepts a reference only from an associate of the cart's business unit, and refuses one on a personal cart, so the error is returned rather than swallowed.
function useSetPurchaseReference( cart: { id: string; version?: string | undefined; },): { setPurchaseReference: (reference: string | null) => Promise<Cart>; isPending: boolean; error: unknown;}| Option | Type | Description |
|---|---|---|
id | string | |
version? | string |
Returns { setPurchaseReference: (reference: string | null) => Promise<Cart>; isPending: boolean; error: unknown; }
useSetShippingMethodThe delivery method.
import { useSetShippingMethod } from "@evolve-storefront/feature-cart/hooks";Changing it can change what checkout asks for next: a pickup method drops the delivery-address section. That follows from the cart the response writes, so nothing here has to coordinate it.
function useSetShippingMethod()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
useSetVatNumberRecord the VAT number of the company the buyer orders for, as given; null clears it.
import { useSetVatNumber } from "@evolve-storefront/feature-cart/hooks";function useSetVatNumber( cart: { id: string; version?: string | undefined; },): { setVatNumber: ( vatNumber: string | null, at?: { version?: string }, ) => Promise<Cart>; isPending: boolean; error: unknown;}| Option | Type | Description |
|---|---|---|
id | string | |
version? | string |
Returns { setVatNumber: ( vatNumber: string | null, at?: { version?: string }, ) => Promise<Cart>; isPending: boolean; error: unknown; }
useUndoCartMergeUndo the merge a sign-in made, on the caller's current cart.
import { useUndoCartMerge } from "@evolve-storefront/feature-cart/hooks";function useUndoCartMerge()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest.
useUpdateLineItemChange line quantities.
import { useUpdateLineItem } from "@evolve-storefront/feature-cart/hooks";function useUpdateLineItem()Returns A React Query mutation: mutate, mutateAsync, isPending and the rest plus warnings.
Other hooks
useAutoSelectShippingMethodChoose the delivery method when there is only one, writing it to the cart — orderPlace reads the selection off the cart, not off the page.
import { useAutoSelectShippingMethod } from "@evolve-storefront/feature-cart/hooks";Three things this effect has to get right: fire on isSuccess rather than truthy data,
never retry a refused write (an infinite mutation loop), and sit above every early
return. Opt-in, and not generalised to payment: money moving is a decision to show.
function useAutoSelectShippingMethod( cart: Pick<Cart, "id" | "version" | "selectedShippingMethod"> | undefined,): { isSelecting: boolean }| Option | Type | Description |
|---|---|---|
id | string | Stable identifier. A bare UUID. |
version | string | Opaque optimistic-concurrency token. Echo it back on every mutation and
never parse or compare it — a stale value returns |
selectedShippingMethod? | ShippingMethod | null | The chosen delivery method (–D3). |
Returns { isSelecting: boolean }
useCartCsvExportA function that downloads the cart as a CSV file, for CartActionsMenu's onExport: headings in the buyer's language and amounts in their notation, so a spreadsheet reads them as numbers.
import { useCartCsvExport } from "@evolve-storefront/feature-cart/hooks";function useCartCsvExport(): (cart: Pick<Cart, "lineItems" | "name">) => voidReturns ( cart: Pick<Cart, "name" | "lineItems">, ) => void
useCartErrorMessageThe shopper-facing message for a failed cart write, or null without an error.
import { useCartErrorMessage } from "@evolve-storefront/feature-cart/hooks";function useCartErrorMessage(error: unknown): string | nullReturns string | null
useCartViewedEmit cartViewed once the cart has answered, and again only when it becomes a different cart: a quantity change is not a new view, and the mutation that made it reports itself.
import { useCartViewed } from "@evolve-storefront/feature-cart/hooks";function useCartViewed(): voidReturns void
useCurrentCartIdWhich cart is the current one, derived from Query.cart.
import { useCurrentCartId } from "@evolve-storefront/feature-cart/hooks";There is no Cart.isCurrent, deliberately: which cart is current is a property
of the caller, not of a cart, so two associates of one business unit would need
two different answers from the same entity. Comparing against the current-cart
query is the derivation that survives that — and it reads from the same cache
entry the mini-cart does, so a switch moves both together.
undefined while the cart query is still settling, so a caller marks nothing
current rather than marking the wrong thing.
function useCurrentCartId(): string | undefinedReturns string | undefined
useExpressPaymentA payment that a provider's component carries on in the page before there is an order, such as PayPal express through Adyen.
import { useExpressPayment } from "@evolve-storefront/feature-cart/hooks";function useExpressPayment( cart: AnalyticsSourceCart, returnUrls: CheckoutReturnUrls,): { start: (method: PaymentMethod) => Promise<ExpressPaymentOutcome>; submit: (details: unknown) => Promise<ExpressPaymentOutcome>; cancel: () => Promise<ExpressP…| Option | Type | Description |
|---|---|---|
lineItems | CartLineItem[] | |
total | TaxedTotalPrice | |
id | string | Stable identifier. A bare UUID. |
totalQuantity | number | Sum of all line quantities — the badge number. |
currency | string | |
successUrl | string | |
cancelUrl | string | |
failureUrl | string |
useLineItemUndoRemove-with-undo: the "item removed.
import { useLineItemUndo } from "@evolve-storefront/feature-cart/hooks";One row at a time, with no timer by default, since a timed undo fails WCAG 2.2.1:
it stays until the next removal or until the list unmounts. undoTimeout from
CartProvider sets a timer anyway; 0 removes immediately, with no row.
function useLineItemUndo<Line>( args: { cart: Cart; timeout?: number | undefined; },): LineItemUndo<Line>| Option | Type | Description |
|---|---|---|
cart | Cart | |
timeout? | number | Overrides |
Returns LineItemUndo<Line>
useQuickAddSuggestionsProducts matching term by name or SKU, for CartQuickAdd: the default variant of each, once the buyer has typed MIN_LENGTH characters and paused.
import { useQuickAddSuggestions } from "@evolve-storefront/feature-cart/hooks";function useQuickAddSuggestions( term: string,): { suggestions: QuickAddSuggestion[]; isSearching: boolean;}Returns { suggestions: QuickAddSuggestion[]; isSearching: boolean; }
useSignInCartMergeWhat the last sign-in in this tab merged into the cart, for CartMergeNotice.
import { useSignInCartMerge } from "@evolve-storefront/feature-cart/hooks";function useSignInCartMerge(): CartMerge | nullReturns CartMerge | null
useStartCheckoutReports checkoutStarted for cart with the route the shopper took, such as "button" from the cart or "apple_pay" from a wallet.
import { useStartCheckout } from "@evolve-storefront/feature-cart/hooks";function useStartCheckout( cart: AnalyticsSourceCart | null | undefined,): (route: CheckoutRoute) => void| Option | Type | Description |
|---|---|---|
lineItems | CartLineItem[] | |
total | TaxedTotalPrice | |
id | string | Stable identifier. A bare UUID. |
totalQuantity | number | Sum of all line quantities — the badge number. |
currency | string |
Returns (route: CheckoutRoute) => void
useQuickOrderA quick order: check(text) reads SKU and quantity lines, lines shows each one resolved (name, net price, stock) or rejected with the reason, and addToCart() puts every resolved line into the active cart in one write.
import { useQuickOrder } from "@evolve-storefront/feature-cart/quick-order";function useQuickOrder( options?: Pick<UseAddToCartOptions, "onAdded">,): { lines: QuickOrderLine[]; lineItems: CartLineItemInput[]; isChecking: boolean; isCheckError: boolean; check: (text: string) => void; removeLine: (sku: string) …| Option | Type | Description |
|---|---|---|
onAdded? | ((result: LineItemsAddedResult) => void) | Overrides |
useCheckoutDeliveryDelivery's data: the methods on offer, select, which puts a chosen method on the cart at once, and save, which writes the address and then the method.
import { useCheckoutDelivery } from "@evolve-storefront/feature-cart/checkout";function useCheckoutDelivery( cart: Cart, options?: { slots?: boolean | undefined; warehouseMethodKey?: string | undefined; },): { methods: UseQueryResult<ShippingMethod[], Error>; dates: UseQueryResult<{ dates: DeliveryDate[]; slot: DeliverySlot | null; }, Error>; select: (methodId: stri…| Option | Type | Description |
|---|---|---|
id | string | Stable identifier. A bare UUID. |
version | string | Opaque optimistic-concurrency token. Echo it back on every mutation and
never parse or compare it — a stale value returns |
lineItems | CartLineItem[] | |
totalQuantity | number | Sum of all line quantities — the badge number. |
currency | string | |
subTotal | TaxedTotalPrice | |
total | TaxedTotalPrice | |
discountCodes | CartDiscountCode[] | |
shippingAddress | CartAddress | null | Where the cart will be delivered. Required before the cart can be quoted and the same address checkout will want, which is why it is set on the cart rather than collected again per flow. MoreRequired but nullable, and the distinction carries weight: |
name? | string | null | Buyer-given name, to tell one cart from another. Null until a cart is named. |
defaultName? | string | null | What to call the cart while it has no name, such as "Drill + 2": its first
product and how many more. Null for an empty cart. See |
owner? | CartOwner | null | Null for a guest cart, which belongs to a session rather than to anyone. |
deliveryRemarks? | string | null | The buyer's note for whoever delivers — a gate code, a delivery window, a loading-bay instruction. MoreAbsent rather than empty when there is none, so a checkout can tell "no note" from "a note the buyer cleared". |
purchaseOrderNumber? | string | null | The buyer's own reference for this purchase, usually a purchase order number. MoreIt belongs to the company rather than to the shopper, so only an associate of the business unit the cart belongs to may record one — a personal cart will never carry it. |
vatNumber? | string | null | The VAT number of the company the buyer orders for, carried to the order. |
vatOutcome? | VatOutcome | null | Which VAT rule the amounts follow and why. Null until there is a delivery address, and where the engine does not decide VAT itself. Under reverse charge or export every line and shipping are taxed at 0%, so the totals hold no VAT. |
discountTotal? | TaxedPrice | null | Every discount on the cart, code-driven ones included — the schema calls it
"sum of all discounts". So a summary that renders a row per MoreA Still taken as a magnitude, not a signed addend. The schema now documents
it as positive ("subtract it, never add it"), but the two engines that
disagreed have not both been re-observed, and |
shippingCosts? | TaxedPrice | null | |
estimatedShippingCosts? | TaxedPrice | null | What shipping will likely cost while no shipping method is set, or null once
|
customerEmail? | string | null | Where the order confirmation goes. |
isGuest? | boolean | True when no customer is attached. Set by the backend, never written here. |
billingAddress? | CartAddress | null | Billed-to address. Nullable for the same reason as |
selectedShippingMethod? | ShippingMethod | null | The chosen delivery method (–D3). |
selectedPaymentMethod? | PaymentMethod | null | The chosen payment method. Selection only — Payment owns the rest. |
amountToPay? | Money | The gross total less what the cart's payments hold or collected. A gift card
lowers this and never |
payments? | CartPayment[] | The cart's payments, oldest first: gift cards, and the one that pays the rest. |
createdAt? | string | |
lastModifiedAt? | string | |
slots? | boolean | |
warehouseMethodKey? | string |
useCheckoutDraftA section's unsaved input, kept by the shell so it outlives the section closing.
import { useCheckoutDraft } from "@evolve-storefront/feature-cart/checkout";function useCheckoutDraft<T>( sectionId: string, initial: T | (() => T),): [T, (next: T | ((previous: T) => T)) => void, () => void]Returns [T, (next: T | ((previous: T) => T)) => void, () => void]
useCheckoutPaymentPayment's data: the methods on offer, and save, which writes the company VAT number, the billing address and the method the shopper picked.
import { useCheckoutPayment } from "@evolve-storefront/feature-cart/checkout";function useCheckoutPayment( cart: Cart, device?: ClientDevice,): { methods: UseQueryResult<PaymentMethod[], Error>; save: (args: { billingAddress: CartShippingAddressInput; paymentMethod: PaymentMethodInput | null; vatNumber?…| Option | Type | Description |
|---|---|---|
id | string | Stable identifier. A bare UUID. |
version | string | Opaque optimistic-concurrency token. Echo it back on every mutation and
never parse or compare it — a stale value returns |
lineItems | CartLineItem[] | |
totalQuantity | number | Sum of all line quantities — the badge number. |
currency | string | |
subTotal | TaxedTotalPrice | |
total | TaxedTotalPrice | |
discountCodes | CartDiscountCode[] | |
shippingAddress | CartAddress | null | Where the cart will be delivered. Required before the cart can be quoted and the same address checkout will want, which is why it is set on the cart rather than collected again per flow. MoreRequired but nullable, and the distinction carries weight: |
name? | string | null | Buyer-given name, to tell one cart from another. Null until a cart is named. |
defaultName? | string | null | What to call the cart while it has no name, such as "Drill + 2": its first
product and how many more. Null for an empty cart. See |
owner? | CartOwner | null | Null for a guest cart, which belongs to a session rather than to anyone. |
deliveryRemarks? | string | null | The buyer's note for whoever delivers — a gate code, a delivery window, a loading-bay instruction. MoreAbsent rather than empty when there is none, so a checkout can tell "no note" from "a note the buyer cleared". |
purchaseOrderNumber? | string | null | The buyer's own reference for this purchase, usually a purchase order number. MoreIt belongs to the company rather than to the shopper, so only an associate of the business unit the cart belongs to may record one — a personal cart will never carry it. |
vatNumber? | string | null | The VAT number of the company the buyer orders for, carried to the order. |
vatOutcome? | VatOutcome | null | Which VAT rule the amounts follow and why. Null until there is a delivery address, and where the engine does not decide VAT itself. Under reverse charge or export every line and shipping are taxed at 0%, so the totals hold no VAT. |
discountTotal? | TaxedPrice | null | Every discount on the cart, code-driven ones included — the schema calls it
"sum of all discounts". So a summary that renders a row per MoreA Still taken as a magnitude, not a signed addend. The schema now documents
it as positive ("subtract it, never add it"), but the two engines that
disagreed have not both been re-observed, and |
shippingCosts? | TaxedPrice | null | |
estimatedShippingCosts? | TaxedPrice | null | What shipping will likely cost while no shipping method is set, or null once
|
customerEmail? | string | null | Where the order confirmation goes. |
isGuest? | boolean | True when no customer is attached. Set by the backend, never written here. |
billingAddress? | CartAddress | null | Billed-to address. Nullable for the same reason as |
selectedShippingMethod? | ShippingMethod | null | The chosen delivery method (–D3). |
selectedPaymentMethod? | PaymentMethod | null | The chosen payment method. Selection only — Payment owns the rest. |
amountToPay? | Money | The gross total less what the cart's payments hold or collected. A gift card
lowers this and never |
payments? | CartPayment[] | The cart's payments, oldest first: gift cards, and the one that pays the rest. |
createdAt? | string | |
lastModifiedAt? | string |
useCheckoutSectionConfirmConfirms the enclosing section, for a section whose save is a form submit rather than CheckoutSectionContinue's click.
import { useCheckoutSectionConfirm } from "@evolve-storefront/feature-cart/checkout";function useCheckoutSectionConfirm(): (value?: unknown) => voidReturns (value?: unknown) => void
useCheckoutSectionIdThe id of the enclosing CheckoutSection, for the parts that act on it.
import { useCheckoutSectionId } from "@evolve-storefront/feature-cart/checkout";function useCheckoutSectionId(): stringReturns string
useCheckoutShellThe enclosing checkout's shell state.
import { useCheckoutShell } from "@evolve-storefront/feature-cart/checkout";function useCheckoutShell(): CheckoutShellValueReturns CheckoutShellValue
useExpressCheckoutThe cart side of a wallet sheet (Apple Pay, Google Pay, PayPal): the wallets on offer, and the callbacks the sheet calls.
import { useExpressCheckout } from "@evolve-storefront/feature-cart/checkout";function useExpressCheckout( cart: Cart, options?: UseExpressCheckoutOptions,): { methods: PaymentMethod[]; isPending: boolean; error: Error | null; onAddressChange: (address: ExpressAddress) => Promise<ShippingMethod[]>; onShippingOptionCh…| Option | Type | Description |
|---|---|---|
id | string | Stable identifier. A bare UUID. |
version | string | Opaque optimistic-concurrency token. Echo it back on every mutation and
never parse or compare it — a stale value returns |
lineItems | CartLineItem[] | |
totalQuantity | number | Sum of all line quantities — the badge number. |
currency | string | |
subTotal | TaxedTotalPrice | |
total | TaxedTotalPrice | |
discountCodes | CartDiscountCode[] | |
shippingAddress | CartAddress | null | Where the cart will be delivered. Required before the cart can be quoted and the same address checkout will want, which is why it is set on the cart rather than collected again per flow. MoreRequired but nullable, and the distinction carries weight: |
name? | string | null | Buyer-given name, to tell one cart from another. Null until a cart is named. |
defaultName? | string | null | What to call the cart while it has no name, such as "Drill + 2": its first
product and how many more. Null for an empty cart. See |
owner? | CartOwner | null | Null for a guest cart, which belongs to a session rather than to anyone. |
deliveryRemarks? | string | null | The buyer's note for whoever delivers — a gate code, a delivery window, a loading-bay instruction. MoreAbsent rather than empty when there is none, so a checkout can tell "no note" from "a note the buyer cleared". |
purchaseOrderNumber? | string | null | The buyer's own reference for this purchase, usually a purchase order number. MoreIt belongs to the company rather than to the shopper, so only an associate of the business unit the cart belongs to may record one — a personal cart will never carry it. |
vatNumber? | string | null | The VAT number of the company the buyer orders for, carried to the order. |
vatOutcome? | VatOutcome | null | Which VAT rule the amounts follow and why. Null until there is a delivery address, and where the engine does not decide VAT itself. Under reverse charge or export every line and shipping are taxed at 0%, so the totals hold no VAT. |
discountTotal? | TaxedPrice | null | Every discount on the cart, code-driven ones included — the schema calls it
"sum of all discounts". So a summary that renders a row per MoreA Still taken as a magnitude, not a signed addend. The schema now documents
it as positive ("subtract it, never add it"), but the two engines that
disagreed have not both been re-observed, and |
shippingCosts? | TaxedPrice | null | |
estimatedShippingCosts? | TaxedPrice | null | What shipping will likely cost while no shipping method is set, or null once
|
customerEmail? | string | null | Where the order confirmation goes. |
isGuest? | boolean | True when no customer is attached. Set by the backend, never written here. |
billingAddress? | CartAddress | null | Billed-to address. Nullable for the same reason as |
selectedShippingMethod? | ShippingMethod | null | The chosen delivery method (–D3). |
selectedPaymentMethod? | PaymentMethod | null | The chosen payment method. Selection only — Payment owns the rest. |
amountToPay? | Money | The gross total less what the cart's payments hold or collected. A gift card
lowers this and never |
payments? | CartPayment[] | The cart's payments, oldest first: gift cards, and the one that pays the rest. |
createdAt? | string | |
lastModifiedAt? | string | |
device? | ClientDevice | |
isShippingMethodOffered? | ((method: ShippingMethod) => boolean) | Leave out a method that needs the full checkout, such as a slot or pickup method. |
maxShippingOptions? | number | How many shipping options the sheet shows. Defaults to 3. |

