React (Reference Theme)
Our reference themes are built with Vite + React:themes/defaultthemes/classic
Component Tree
The reference theme follows this hierarchy:| Layer | Purpose |
|---|---|
ThemeSettingsProvider | Fetches and merges theme settings, provides them via context |
ThemeStyleApplier | Reads resolved settings via useThemeSettings() and calls applyThemeSettingsToCss() |
InitialDataProvider | Passes injected initial data (window.__SHOPPEX_INITIAL__) down the tree |
ToastProvider | Notification system |
BrowserRouter | React Router for client-side navigation |
AppShell | Layout shell with Header, Routes, and Footer |
ThemeSettingsProvider wraps InitialDataProvider β settings are available everywhere, including in the data layer.Where SDK Init Happens
- HTML loads the SDK via CDN:
themes/default/index.html - The app bootstraps + calls
shoppex.init(...):themes/default/src/main.tsx
Resolve the store slug
From subdomain (
*.myshoppex.io), env var (VITE_SHOP_SLUG), or custom domain resolution via shoppex.resolveStoreByDomain().Check for initial data
Reads
window.__SHOPPEX_INITIAL__ (injected during build) and passes it to App as a prop.Where Data Loading Happens: useStore()
useStore() is where storefront data is resolved. It does two things in order:
- Use InitialDataContext for first paint β if the page was pre-rendered (or the platform injected
window.__SHOPPEX_INITIAL__), the data is available immediately. - Revalidate via the SDK β even if initial data exists, your theme should still call
shoppex.getStorefront()aftershoppex.init()to protect against stale HTML (for example right after a migration/import). You can do this in the background and update state once the fresh response arrives.
Return Value
| Field | Type | Description |
|---|---|---|
store | Shop | null | Store metadata (name, logo, settings) |
products | Product[] | All products |
groups | ProductGroup[] | Product groups/collections |
isLoading | boolean | true while data is being fetched |
error | string | null | Error message if fetch failed |
The fetched storefront data is cached at module scope. Subsequent
useStore() calls in other components reuse the same data without re-fetching.Cart UI: useCartSync() and emitCartChanged()
useCartSync and emitCartChanged are theme-level patterns, not SDK features. The SDK manages cart data; these helpers keep the UI in sync.CartSnapshot Interface
useCartSync() returns a CartSnapshot β a reactive view of the current cart:
| Field | Type | Description |
|---|---|---|
items | CartItem[] | Current cart items |
itemCount | number | Number of distinct line items |
totalQuantity | number | Sum of all item quantities |
totalPrice | number | Computed total price |
totalPriceIsEstimate | boolean | Whether the price is an estimate (e.g. missing price data) |
emitCartChanged()
After any cart mutation, dispatch a custom event so all listeners re-read the cart:
useCartSync()
The hook listens for the custom event and storage events (for cross-tab sync) and returns the current cart snapshot:
getSnapshot() function calls shoppex.getCart() and shoppex.getCartStats() to build the snapshot.
Usage Pattern
addToCart, updateCartItem, removeFromCart, and clearCart. Always call emitCartChanged() after the SDK method.
Theme Settings: useThemeSettings() and applyThemeSettingsToCss()
ThemeSettingsProvider
The provider does three things at startup:Resolve defaults from theme.config.ts
Reads the settings schema and extracts all
default values into a ResolvedThemeSettings object.Fetch published overrides
If the SDK is initialized, calls
shoppex.fetchPublishedThemeSettings(shopSlug) to get merchant-configured values.useThemeSettings()
Returns the fully resolved settings from context (defaults merged with published overrides):
useThemeSettings() must be called inside ThemeSettingsProvider. It throws if used outside the provider tree.applyThemeSettingsToCss()
Maps resolved theme settings to CSS custom properties on document.documentElement. Called automatically by ThemeStyleApplier whenever settings change.
| Settings Path | CSS Variable | Description |
|---|---|---|
colors.background | --surface | Background color |
colors.surface | --card-bg | Card/surface color |
colors.primary | --brand-600 | Primary brand color |
colors.primaryDark | --brand-700 | Darker brand variant (fallback: colors.secondary, then darken primary 10%) |
colors.text | --text | Main text color |
colors.textMuted | --text-muted | Muted text color |
colors.textContrast | --text-contrast | Contrast text color |
colors.border | --border | Border color |
colors.muted | --muted | Muted background |
colors.accent | --accent | Accent color |
colors.hover | --hover | Hover state color |
colors.success | --success | Success color |
colors.error | --destructive | Error/destructive color |
typography.fontFamily | --font-family-body | Body font family |
typography.headingFont | --font-family-heading | Heading font (falls back to body) |
typography.fontSize | --font-size-base | Base font size in px |
effects.borderRadius | --radius | Global border radius in rem |
buttons.borderRadius | --button-radius | Button-specific radius in px |
inputs.height | --input-height | Input height in px |
inputs.borderRadius | --input-border-radius | Input-specific radius in px |
header.height | --header-height | Header height in px |
Color values are stored as space-separated RGB triplets (e.g.
124 58 237), not hex. Use rgb(var(--brand-600)) in CSS.SSR / SSG
If you need SSR/SSG, see:- Pre-Rendering (platform injection + theme-owned SSG)
- Build Pipeline (build steps)
Next Steps
Cart & Checkout
Full cart API, coupon validation, and checkout handoff.
Theme Settings
How the settings schema works and how merchants configure your theme.
Theme Config
Define your themeβs settings schema in theme.config.ts.
SDK Reference
Complete SDK method reference.