NUMU Docs
Contact
APIThemes
Partner Apps
APIThemes
Partner Apps
  1. Theme SDK
  • 🗂️ Themes overview
  • 🚀 Start here
  • Glossary
  • Theme engine
    • Architecture
    • BYOT contract
    • Customizer
    • Federation runtime
    • Page data contract
    • Theme manifest
  • Theme SDK
    • Components
    • Federation helpers
    • Hooks
    • SDK overview
    • Type definitions
  • CLI & Vite plugin
    • CLI commands
    • CLI overview
    • Lint rules
    • Section library
    • Vite plugin
  • Storefront host
    • API proxies
    • Built-in fallbacks
    • BYOT fork
    • Routing
    • Storefront overview
  1. Theme SDK

SDK overview

@numueg/theme-sdk — the React hooks + components every NUMU theme consumes.

Install#

Themes get the SDK as a peer dep (externalized at build time, resolved by the storefront's import map at runtime):
{
  "peerDependencies": {
    "@numueg/theme-sdk": "^0.6.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}
Themes import via bare specifier:
import { useCart, AddToCartButton, Money } from "@numueg/theme-sdk";

What the SDK provides#

Hooks (25+)#

HookPurpose
useShop()Store name, currency, domain helpers
useThemeSettings()Resolved customizer state
useLocalization(), useDirection(), useTranslation()i18n + RTL
useCurrency()Multi-currency presentment
usePage()Current page type + data (route-aware)
useProduct(), useProductOptional()Product context
useProducts()Paginated product list
useCollection(), useCollectionOptional(), useCollections()Categories
useVariantSelection(product)PDP variant picker state machine
useCart()Cart contents + mutations
useCustomer()Logged-in customer or null
useCustomerActions()login/register/logout/recover/reset
useCustomerAddresses()Address book CRUD
useOrders(), useOrder()Order history
useReorder()"Buy again"
useGiftCardBalance()Checkout-step gift card probe
useCheckout()Programmatic multi-step checkout driver
useShippingRates()Resolve shipping options for an address
useNavigation(handle)Merchant-defined nav menus
useSearch()Predictive + full search
useAnalytics()track(event, payload)
useRelatedProducts(productId)Same-category siblings
useWishlist()Wishlist persistence
useApp(slug)App-provided data (Phase 9 platform)
useSection(), useSectionOptional()Current section context (settings + blocks)
useImage(), useMoney()Formatting helpers
Detailed reference: Hooks.

Components (15+)#

ComponentPurpose
<NuMuProvider>Root provider — wraps the theme tree
<ProductProvider>, <CollectionProvider>Override context for nested trees
<Section>, <Block>Render sections + blocks defined in schemas
<Image>Lazy + responsive + content-hashed srcset
<Money>Currency formatter that respects useCurrency
<Link>Internal link with subdomain awareness
<Form>Server-action form with progressive enhancement
<AddToCartButton>Variant-aware add-to-cart with built-in UX states
<ProductCard>Opinionated default card
<CollectionCard>Opinionated default card
<RichText html>DOMPurify-sanitized HTML renderer
<CurrencySwitcher>, <LocaleSwitcher>Storefront toggles
<CookieConsent>Cookie consent banner (GDPR, Phase 5.6)
Detailed reference: Components.

Utilities#

findVariantByOptions(product, selection) — variant resolution
defaultVariant(product) — first in-stock variant or fallback
availableValues(product, selection) — which axis values still resolve to in-stock variants
assetUrl("path") — resolve a theme asset URL (content-hashed)
sanitizeHtml(html) — same DOMPurify config <RichText> uses
resolveThemeSettings(raw) — legacy field normalizer (rarely needed in themes)
registerSdkSingleton, getSdkSingleton — federation runtime helpers (internal)

The minimum theme#

// src/main.tsx
import { defineThemeEntry, usePage, useShop } from "@numueg/theme-sdk";

function App() {
  const shop = useShop();
  const page = usePage();
  return (
    <div>
      <h1>{shop.name}</h1>
      <p>Current page: {page.type}</p>
    </div>
  );
}

// defineThemeEntry wraps <NuMuProvider> (plus catalog, navigation, and
// global style tokens) around your app and returns BOTH entry points the
// host calls — you never touch createRoot or the mount container yourself:
//   mount(el, ctx)  — client mount/hydrate into the host-supplied element
//   createApp(ctx)  — server render (renderToString) for SSR
const entry = defineThemeEntry(() => <App />);

export const mount = entry.mount;
export const createApp = entry.createApp;
That's a valid, installable theme. The customizer will show it. It renders nothing useful — but numu-theme dev previews it, numu-theme build compiles it, numu-theme submit ships it. Because it exports createApp, the host can server-render it too.

Conventions used throughout#

*Optional() variants#

Hooks like useProductOptional() return null instead of throwing when no context is in scope. Use these in sections that might render outside a <ProductProvider> (e.g. a quick-add card on a collection page).
// Throws when used outside ProductContext:
const product = useProduct();

// Returns null instead:
const product = useProductOptional();
if (!product) return <div>No product in context</div>;

Money is in cents#

unit_price, total, subtotal, amount — all in integer minor units (cents, piasters). Divide by 100 for display, or use <Money> / useMoney().

Snapshot-vs-live prices#

For cart line items, unit_price is the snapshot at add-time and current_price is the live price. Use the snapshot for the order amount; show "price changed" UI when price_changed is true.

Variant-aware everything#

When a product has variants, the cart line, order line, and checkout payload all carry a variant_id. The SDK's variant helpers normalize the API surface so you don't have to special-case "products with variants" vs "products without."

Importing from sub-paths#

The SDK exposes only the top-level @numueg/theme-sdk for now. There's no @numueg/theme-sdk/hooks or @numueg/theme-sdk/components. Tree-shaking handles unused code in your bundle.
The single exception is the JSX runtime (used internally by the federation runtime):
"@numueg/theme-sdk/jsx-runtime"
Themes never import this directly.

TypeScript#

Strict mode + tsconfig strict: true is recommended. The SDK ships with full .d.ts files. Common gotchas:
useCart() returns { cart, addItem, removeItem, updateQuantity, applyDiscount, removeDiscount, updateNote, clearCart, loading } — destructure what you need.
useCustomer() returns Customer | null — branch on it.
usePage() returns a discriminated union by page.type — TypeScript narrows after a switch.

Versioning#

The SDK follows semver:
Patch — Bug fixes, no surface change
Minor — New hooks/components, additive prop changes
Major — Removed/renamed exports, prop signature changes
Themes pin via peerDependencies with ^x.y.z so patch + minor updates auto-apply. Major bumps require a theme code change.
Modified at 2026-09-24 13:03:12
Previous
Hooks
Next
Type definitions
Built with