React to cart events

Run code when the cart changes by subscribing to Salla SDK events.

Use this when your UI or analytics must follow the cart: a badge count, a mini-cart, a "you added..." message.

Goal: a component that shows the live cart count.

The Salla SDK (Salla in prose, window.salla in code) emits events such as cart::updated. You subscribe in a useEffect and unsubscribe on cleanup. The SDK can finish loading after the page hydrates, so read it inside the effect, never at module scope. The full event list and the rules are in Salla SDK and events.

Write a subscription hook

It subscribes by event name, and removes the same function on cleanup. If the SDK is not ready yet, it waits for the theme::ready document event. The reference theme's mobile bottom bar uses this pattern for its cart badge.

app/hooks/useCartUpdated.ts
import { useEffect } from 'react';

type CartSummary = { count?: number | string | null };

export function useCartUpdated(onUpdated: (summary?: CartSummary) => void) {
  useEffect(() => {
    const listener = (...args: unknown[]) => onUpdated(args[0] as CartSummary | undefined);
    let bound = false;

    const bind = () => {
      const event = window.salla?.event;
      if (bound || !event?.on) return;
      event.on('cart::updated', listener);
      bound = true;
    };

    bind();
    document.addEventListener('theme::ready', bind);
    return () => {
      document.removeEventListener('theme::ready', bind);
      if (bound) window.salla?.event?.off?.('cart::updated', listener);
    };
  }, [onUpdated]);
}

Use it in a component

Wrap the callback in useCallback so the effect does not resubscribe on every render.

app/components/CartWatcher.tsx
import { useCallback, useState } from 'react';
import { useCartUpdated } from '../hooks/useCartUpdated';

export function CartWatcher() {
  const [count, setCount] = useState(0);
  const onUpdated = useCallback((summary?: { count?: number | string | null }) => {
    setCount(Number(summary?.count ?? 0));
  }, []);
  useCartUpdated(onUpdated);
  return <span>{count}</span>;
}

Check it worked

Add a product to the cart: count updates without a reload. Navigate away and back, then add again: it still updates once, not twice.

Traps

  • Do not mix the two ways to subscribe. Typed helpers exist (salla.cart.event.onUpdated, onItemAdded, onItemUpdated, onItemDeleted, each with a matching off...), but there is no salla.cart.event.off(name, cb). A name-based listener is removed with salla.event.off.
  • Subscribe by name in components that mount often. The reference theme avoids onUpdated there because the helper wraps your callback and it leaked listeners in its case.
  • window.salla is undefined during server rendering, and a stub without event until the SDK loads. Guard the member (window.salla?.event?.on), subscribe inside useEffect, and use theme::ready as above.
  • The initial count is not an event. The reference theme also reads salla.storage.get('cart.summary.count') once on mount.
  • The payload is loosely typed. Treat it as optional and fall back to a default.

Next

On this page