Skip to content

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; })
OptionTypeDescription
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; })
OptionTypeDescription
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)
OptionTypeDescription
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; })
OptionTypeDescription
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; })
OptionTypeDescription
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; })
OptionTypeDescription
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; })
OptionTypeDescription
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; })
OptionTypeDescription
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)
OptionTypeDescription
onAdded?((result: LineItemsAddedResult) => void)

Overrides CartProvider's onLineItemsAdded and CartAddedSheet for this call site. An override, not an addition: a surface that opens a cross-sell dialog does not also want the app-wide drawer.

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 cartItemAdded. Undoing a removal is the in-package case — a restored line must not pop the mini-cart open.

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)
OptionTypeDescription
onAdded?((result: LineItemsAddedResult) => void)

Overrides CartProvider's onLineItemsAdded and CartAddedSheet for this call site. An override, not an addition: a surface that opens a cross-sell dialog does not also want the app-wide drawer.

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 cartItemAdded. Undoing a removal is the in-package case — a restored line must not pop the mini-cart open.

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…)
OptionTypeDescription
documentTypedDocumentNode<Record<Field, Payload>, Variables>
fieldField
mutationKey?readonly unknown[]

Tags the mutation, so useIsMutating can count the writes that share it.

resolveVariables?((variables: Variables) => Promise<Variables>)

Last chance to complete the variables, run once the session exists and before the request goes out. useAddToCart names the cart to write to here, because which cart is current can only be resolved against a session — and ensureSession may have just created the one this write gets.

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 CART_VERSION_CONFLICT, against the cart as the server has it now: return the variables to resend, "done" when that cart already shows the write took effect, or null to give up and report the conflict.

onWritten?((cart: Cart, variables: Variables, warnings: TypedError[], payload: Payload | null) => void)

Runs after the authoritative cart is in the cache. warnings are the non-fatal codes the server returned with it (a partial OUT_OF_STOCK add); payload is the whole response, null when a retry found the write already applied.

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)
OptionTypeDescription
successUrlstring
cancelUrlstring
failureUrlstring

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)
OptionTypeDescription
payCheckoutPay
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 }>
OptionTypeDescription
idstring
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;
}
OptionTypeDescription
idstring
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;
}
OptionTypeDescription
idstring
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;
}
OptionTypeDescription
idstring
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 }
OptionTypeDescription
idstring

Stable identifier. A bare UUID.

versionstring

Opaque optimistic-concurrency token. Echo it back on every mutation and never parse or compare it — a stale value returns CART_VERSION_CONFLICT. Typed string, not a number, so ETags and OCC timestamps both fit.

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">) => void

Returns ( 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 | null

Returns 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(): void

Returns 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 | undefined

Returns 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…
OptionTypeDescription
lineItemsCartLineItem[]
totalTaxedTotalPrice
idstring

Stable identifier. A bare UUID.

totalQuantitynumber

Sum of all line quantities — the badge number.

currencystring
successUrlstring
cancelUrlstring
failureUrlstring
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>
OptionTypeDescription
cartCart
timeout?number

Overrides CartProvider's undoTimeout for this list.

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 | null

Returns 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
OptionTypeDescription
lineItemsCartLineItem[]
totalTaxedTotalPrice
idstring

Stable identifier. A bare UUID.

totalQuantitynumber

Sum of all line quantities — the badge number.

currencystring

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) …
OptionTypeDescription
onAdded?((result: LineItemsAddedResult) => void)

Overrides CartProvider's onLineItemsAdded and CartAddedSheet for this call site. An override, not an addition: a surface that opens a cross-sell dialog does not also want the app-wide drawer.

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…
OptionTypeDescription
idstring

Stable identifier. A bare UUID.

versionstring

Opaque optimistic-concurrency token. Echo it back on every mutation and never parse or compare it — a stale value returns CART_VERSION_CONFLICT. Typed string, not a number, so ETags and OCC timestamps both fit.

lineItemsCartLineItem[]
totalQuantitynumber

Sum of all line quantities — the badge number.

currencystring
subTotalTaxedTotalPrice
totalTaxedTotalPrice
discountCodesCartDiscountCode[]
shippingAddressCartAddress | 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.

More

Required but nullable, and the distinction carries weight: null is a cart with no destination, while a missing field would mean nobody selected it. Both document sets select it, so the second case cannot arise — and anything gating UI on this reads "no address" rather than "no data".

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 cartDisplayName.

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.

More

Absent 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.

More

It 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 discountCodes and a row for this double-counts; see cartDiscountRows.

More

A TaxedPrice, which is what a summary needs: it used to be a bare Money carrying neither a tax basis nor a sign, so a gross summary could only estimate it by grossing the net figure up at the cart's rate — and a mixed-rate cart had no client-side answer at all. Both bases are now carried, so read the one the summary is showing.

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 Math.abs costs nothing.

shippingCosts?TaxedPrice | null
estimatedShippingCosts?TaxedPrice | null

What shipping will likely cost while no shipping method is set, or null once shippingCosts is known or the backend has nothing to base it on. Not in total.

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 shippingAddress.

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 total. Optional so a cart built by hand need not set it.

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?…
OptionTypeDescription
idstring

Stable identifier. A bare UUID.

versionstring

Opaque optimistic-concurrency token. Echo it back on every mutation and never parse or compare it — a stale value returns CART_VERSION_CONFLICT. Typed string, not a number, so ETags and OCC timestamps both fit.

lineItemsCartLineItem[]
totalQuantitynumber

Sum of all line quantities — the badge number.

currencystring
subTotalTaxedTotalPrice
totalTaxedTotalPrice
discountCodesCartDiscountCode[]
shippingAddressCartAddress | 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.

More

Required but nullable, and the distinction carries weight: null is a cart with no destination, while a missing field would mean nobody selected it. Both document sets select it, so the second case cannot arise — and anything gating UI on this reads "no address" rather than "no data".

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 cartDisplayName.

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.

More

Absent 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.

More

It 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 discountCodes and a row for this double-counts; see cartDiscountRows.

More

A TaxedPrice, which is what a summary needs: it used to be a bare Money carrying neither a tax basis nor a sign, so a gross summary could only estimate it by grossing the net figure up at the cart's rate — and a mixed-rate cart had no client-side answer at all. Both bases are now carried, so read the one the summary is showing.

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 Math.abs costs nothing.

shippingCosts?TaxedPrice | null
estimatedShippingCosts?TaxedPrice | null

What shipping will likely cost while no shipping method is set, or null once shippingCosts is known or the backend has nothing to base it on. Not in total.

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 shippingAddress.

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 total. Optional so a cart built by hand need not set it.

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) => void

Returns (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(): string

Returns string

useCheckoutShellThe enclosing checkout's shell state.
import { useCheckoutShell } from "@evolve-storefront/feature-cart/checkout";
function useCheckoutShell(): CheckoutShellValue

Returns 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…
OptionTypeDescription
idstring

Stable identifier. A bare UUID.

versionstring

Opaque optimistic-concurrency token. Echo it back on every mutation and never parse or compare it — a stale value returns CART_VERSION_CONFLICT. Typed string, not a number, so ETags and OCC timestamps both fit.

lineItemsCartLineItem[]
totalQuantitynumber

Sum of all line quantities — the badge number.

currencystring
subTotalTaxedTotalPrice
totalTaxedTotalPrice
discountCodesCartDiscountCode[]
shippingAddressCartAddress | 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.

More

Required but nullable, and the distinction carries weight: null is a cart with no destination, while a missing field would mean nobody selected it. Both document sets select it, so the second case cannot arise — and anything gating UI on this reads "no address" rather than "no data".

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 cartDisplayName.

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.

More

Absent 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.

More

It 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 discountCodes and a row for this double-counts; see cartDiscountRows.

More

A TaxedPrice, which is what a summary needs: it used to be a bare Money carrying neither a tax basis nor a sign, so a gross summary could only estimate it by grossing the net figure up at the cart's rate — and a mixed-rate cart had no client-side answer at all. Both bases are now carried, so read the one the summary is showing.

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 Math.abs costs nothing.

shippingCosts?TaxedPrice | null
estimatedShippingCosts?TaxedPrice | null

What shipping will likely cost while no shipping method is set, or null once shippingCosts is known or the backend has nothing to base it on. Not in total.

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 shippingAddress.

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 total. Optional so a cart built by hand need not set it.

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.