Skip to content

CartAddBundleButton

Adds a product and the extras chosen with it in one call, as a bundle. The extras get the bundle's discount for as long as the product's line is in the cart. Confirms like CartAddProductButton, and renders its error as a sibling.

import { CartAddBundleButton } from "@evolve-storefront/feature-cart/cart-add-bundle-button";

Renders inside CartProvider.

Preview

DefaultOpen in Storybook ↗

Usage

One click adds the product and every extra; the confirmation lists all three.

const selection = useBundleSelection({ sku: variant.sku, items });
<CartAddBundleButton
sku={variant.sku}
extras={selection.extras}
disabled={!selection.canAdd}
/>;

Props

PropTypeDescription
skustring

The page's product, as the variant the shopper chose.

extrasreadonly string[]

SKUs of the extras, each added as its own line linked to the product's.

isPending?boolean

The action is running. The button keeps its label, so its width and accessible name hold, shows a spinner and is aria-busy. It stays focusable rather than disabled, so focus is not dropped mid-save; clicks and the form submit it would trigger are ignored. Not supported with asChild.

type?"reset" | "button" | "submit"
variant?ButtonVariant
tone?ButtonTone
isIconOnly?boolean

The button has no visible label, so it is square. Structural rather than a size: it says the button has nothing to be wide for, and says nothing about how big — the brand's control tokens still decide that.

More

Not inferred from the children. A kebab menu is as often a glyph or an SVG as an <Icon>, and a visually-hidden label — the accessible thing to add — would break any :only-child predicate silently.

asChild?boolean
data-component?undefined

A button's identity is not a caller's to rename — see buttonProps. Typed away so a call site renaming it fails to compile rather than passing an attribute that is silently discarded.

quantity?number

Units of the product, and of each extra.

onAdded?((result: LineItemsAddedResult) => void)

Overrides CartProvider's onLineItemsAdded and CartAddedSheet for this button.

children?ReactNode

Any other props go to the root element, like on a plain HTML element.

Examples

RefusedA refused bundle is said beside the button, and nothing is added.
<CartAddBundleButton sku={variant.sku} extras={selection.extras} />;
Open in Storybook ↗