Managing the cart (Shopify Hydrogen)

This is for:

Developer

When building Coveo-powered commerce interfaces using server-side rendering (SSR), it’s crucial to keep the Headless cart state synchronized with the Shopify cart.

When a user interacts with the cart, such as adding or removing a product, the cart state must be updated in the Headless engine and the Shopify cart.

Convert the Shopify cart to a Headless cart

When fetching the static state of the app, you must retrieve the Shopify cart state and convert it to the Headless cart state.

The following example shows how to convert the Shopify cart to a Headless cart:

// lib/map-coveo-shopify.cart-ts

import type {CartItem as HeadlessCartItem} from '@coveo/headless-react/ssr-commerce';
import type {
  CartLine,
  ComponentizableCartLine,
  CartReturn,
} from '@shopify/hydrogen/storefront-api-types';

function mapShopifyCartToCoveoCart(cart: CartReturn | null) { 1
  return {
    items: cart?.lines.nodes.map((node) => {
      return mapShopifyMerchandiseToCoveoCartItem(node);
    }),
  };
}

export function mapShopifyMerchandiseToCoveoCartItem( 2
  node: CartLine | ComponentizableCartLine,
): HeadlessCartItem {
  const {merchandise} = node;
  const selectedColor = merchandise.selectedOptions.find(
    (opt) => opt.name === 'Color',
  );
  return {
    productId: `${merchandise.product.handle.toUpperCase()}_${colorToShorthand(
      selectedColor?.value || '',
    )}`,
    name: merchandise.product.title,
    price: Number(merchandise.price.amount),
    quantity: node.quantity,
  };
}

export function colorToShorthand(color: string) {
  const colorMap: {[key: string]: string} = {
    'birchwood brown': 'BB',
    black: 'BK',
    blue: 'BL',
    brown: 'BR',
    clear: 'CL',
    cyan: 'CY',
    'deep red': 'DR',
    'forest green': 'FG',
    gray: 'GY',
    green: 'GN',
    grey: 'GY',
    khaki: 'KH',
    lime: 'LM',
    'multi color': 'MC',
    'multi-colored': 'MC',
    natural: 'NT',
    navy: 'NY',
    'olive green': 'OG',
    olive: 'OL',
    one: '01',
    orange: 'OR',
    pink: 'PK',
    purple: 'PL',
    red: 'RD',
    'rustic yellow': 'RY',
    silver: 'SV',
    'sky blue': 'SB',
    white: 'WH',
    yellow: 'YL',
    beige: 'BG',
    gold: 'GD',
    striped: 'ST',
    neon: 'NE',
    pastel: 'PS',
    tan: 'TN',
  };

  return colorMap[color.toLowerCase() as keyof typeof colorMap] || 'BK';
}
1 Define a mapShopifyCartToCoveoCart method that converts a Shopify cart to a Headless cart.
2 The mapShopifyMerchandiseToCoveoCartItem method converts a Shopify CartLine to a Headless CartItem object.

Modify the cart state based on user interactions

When a user interacts with the cart, such as adding or removing a product, you must update both the Shopify cart and the Headless cart state. This section focuses on the Headless-specific implementation. For details on updating the Shopify cart, refer to the Shopify documentation.

Note

To use the components defined in the following section, make sure you have set up a cart handler and can read cart data.

This setup provides access to the Shopify cart, which is passed to the components as a prop to access objects such as lines and lineIds.

Add cart items

The add-to-cart button component is often included directly on the product listing page (PLP), product detail page (PDP), or the search results page.

import {CartForm} from '@shopify/hydrogen';
import {useCart} from '~/lib/commerce-engine.ts';
import {Product} from '@coveo/headless-react/ssr-commerce';

export default function AddToCartButton({
  product,
  lines,
}: {
  product: Product;
  lines: { quantity: number }[];
}) {
  const coveoCart = useCart(); 1

  const currentQuantity = 2
    coveoCart.state.items.find((item) => item.productId === product.id)
      ?.quantity || 0;
  const quantityToAdd = lines[0]?.quantity ?? 0;
  const newQuantity = currentQuantity + quantityToAdd;

  return (
    <CartForm
      route="/cart"
      action={CartForm.ACTIONS.LinesAdd} 3
      inputs=
    >
      <button
        onClick={() => { 4
          coveoCart.methods?.updateItemQuantity({
            name: product.title,
            price: product.price,
            productId: product.id,
            quantity: newQuantity,
          });
        }}
      >
        Add to cart
      </button>
    </CartForm>
  );
}
1 Use the useCart hook to retrieve the Headless cart state. Ensure that the cart controller was defined when creating your engine configuration.
2 Calculate the current quantity of the product in the cart.
3 Use the CartForm component to submit the cart update as specified in the Shopify documentation.
4 Update the cart item quantity by calling the updateItemQuantity method.

Update cart items

When a user updates an item’s quantity in the cart, ensure the Headless cart state reflects the new quantity.

import {CartForm} from '@shopify/hydrogen';
import type {CartLineUpdateInput} from '@shopify/hydrogen/storefront-api-types';
import type {CartItem} from '@coveo/headless-react/ssr-commerce';
import {useCart} from '~/lib/commerce-engine.ts';

export default function UpdateCartItemsButton({
  cartItem,
  lines,
  newQuantity,
}: {
  cartItem: CartItem;
  lines: CartLineUpdateInput[];
  newQuantity: number;
}) {
  const coveoCart = useCart();

  return (
    <CartForm
      route="/cart"
      action={CartForm.ACTIONS.LinesUpdate} 1
      inputs=
    >
      <button
        type="button"
        onClick={() => {
          coveoCart.methods?.updateItemQuantity({ 2
            ...cartItem,
            quantity: newQuantity,
          });
        }}
      >
        Update cart
      </button>
    </CartForm>
  );
}
1 Use the CartForm component to submit the cart update as specified in the Shopify documentation.
2 Update the cart item quantity using the updateItemQuantity method.

Remove cart items

When a user removes an item from the cart, update the Headless cart state by setting the item’s quantity to 0.

import { CartForm } from '@shopify/hydrogen';
import type { CartItem } from '@coveo/headless-react/ssr-commerce';
import { useCart } from '~/lib/commerce-engine.ts';

export default function RemoveCartItemButton({
  lineIds,
  cartItem,
}: { lineIds: string[]; cartItem: CartItem }) {
  const coveoCart = useCart();
  return (
    <CartForm
      route="/cart"
      action={CartForm.ACTIONS.LinesRemove} 1
      inputs=
    >
      <button
        type="button"
        onClick={() => {
          coveoCart.methods?.updateItemQuantity({ ...cartItem, quantity: 0 }); 2
        }}
      >
        Remove items
      </button>
    </CartForm>
  );
}
1 Use the CartForm component to submit the cart update as specified in the Shopify documentation.
2 Update the cart item quantity to 0 using the updateItemQuantity method.