Behio Storefront SDK
Frameworks

React + Vite

React enhancements with the actual SDK hooks and server-authoritative cart state

Provider

Install @behio/storefront-sdk, React and @tanstack/react-query. Pass the public API key to the provider; it creates its own client. There is no client prop.

src/Providers.tsx
import { BehioProvider } from '@behio/storefront-sdk/react';
import type { ReactNode } from 'react';

export function Providers({ apiKey, children }: { apiKey: string; children: ReactNode }) {
  return <BehioProvider apiKey={apiKey} storage="localStorage">{children}</BehioProvider>;
}

This browser-storage setup is for direct browser SDK calls. A premium storefront must render its initial catalog and cart on the server; Vite SPA rendering alone does not meet that requirement. Use your SSR framework's per-request client/cache and pass non-secret initial data to React. With HTTP-only sessions, use your server's session-bound actions/API instead of browser token storage.

Cart interactions

src/CartItems.tsx
import { useState } from 'react';
import { useCart } from '@behio/storefront-sdk/react';

export function CartItems() {
  const { cart, isEmpty, removeItem, isRemoving, error } = useCart();
  const [message, setMessage] = useState('');
  if (error) return <p role="alert">The cart is unavailable. Please retry.</p>;
  if (!cart) return <p role="status">Loading cart…</p>;
  if (isEmpty) return <p>Your cart is empty.</p>;

  async function remove(id: string) {
    setMessage('');
    try { await removeItem(id); }
    catch { setMessage('The item could not be removed. Please retry.'); }
  }

  return <section>
    {message && <p role="alert">{message}</p>}
    {cart.items.map(item => <article key={item.id}>
      <h2>{item.product.name}</h2>
      <p>{item.quantity} × {item.unitPrice === null ? 'Unavailable' : item.unitPrice}</p>
      <button disabled={isRemoving} onClick={() => remove(item.id)}>Remove</button>
    </article>)}
    {cart.bundleLines.map(line => <article key={line.id}>
      <h2>{line.bundleName}</h2><p>Bundle quantity: {line.quantity}</p>
    </article>)}
    {cart.totalsAvailable
      ? <p>Goods total: {cart.grandTotal} {cart.currency}</p>
      : <p>Resolve unavailable items before checkout.</p>}
  </section>;
}

Seed the shared cart query before rendering this component. The loading branch is an explicit fallback for an unseeded browser integration, not a substitute for SSR. The sample only demonstrates ordinary-item removal; add bundle actions, localized money formatting and the remaining cart controls for a complete shop. Use the server's quantityControls instead of assuming a quantity step of one.

useCart also exposes addItem(productId, quantity), updateQuantity(itemId, quantity), clear, applyDiscount, removeDiscount and merge. Catch failed mutations and leave the current server snapshot intact.

Checkout and authentication

Use useCheckoutPreview().preview(input) to obtain a price review. After the shopper accepts it, call useCheckout().createOrder({...input, previewToken}). The pending property is isCreating. Build CheckoutInput from the actual form and merchant settings; see Cart and checkout hooks.

Use useAuth().login(email, password) and useAuth().logout() for browser-managed sessions. The provider restores its configured storage and notifies dependent hooks after page reload. Do not store the entire SdkResult as an auth token or introduce a separate storage key that the provider does not read.

On this page