StoreFuse uses a child theme system that keeps your customizations safe across core updates. You can override any component from the core theme without modifying core files.
StoreFuse themes use a component registry pattern:
- Core Theme (
@storefuse/theme-core) exports a registry of all components - Child Theme (your custom theme) exports a registry with only the components you override
- Theme Engine resolves components: child first, then core fallback
If child theme has component → Use child version
Else → Use core version
This is implemented in @storefuse/core/theme-engine.
Create a theme-child directory in your storefront app:
cd apps/storefront
mkdir -p theme-child/componentsCreate theme-child/index.ts:
export const childThemeRegistry = {
Header: () => import("./components/Header"),
};Create theme-child/components/Header.tsx:
export default function CustomHeader() {
return (
<header className="bg-purple-600 text-white py-4">
<h1>My Custom Store</h1>
</header>
);
}Update storefuse.config.ts:
export default defineStoreFuseConfig({
theme: {
core: "@storefuse/theme-core",
child: "./theme-child",
},
// ... rest of config
});Use @storefuse/theme-child-template as a starting point:
pnpm add @storefuse/theme-child-templateOr create your own package:
mkdir packages/themes/my-custom-theme
cd packages/themes/my-custom-theme
pnpm initYou can override any of these components from @storefuse/theme-core:
Header- Site header with logo and navigationFooter- Site footerNavigation- Main navigation menuLogo- Site logoContainer- Content container wrapperGrid- CSS Grid layout componentSection- Page section wrapper
ProductCard- Product card in listingsProductImage- Product image with zoom/galleryProductGrid- Grid of productsProductList- List view of productsProductDetailPage- Full product detail page
CategoryPage- Category listing page
AddToCartButton- Add to cart buttonCartItem- Single cart itemCartSummary- Cart totals and summaryCartPage- Full cart page
Button- Button componentInput- Input field componentBadge- Badge/label componentPrice- Price display with formatting
When overriding a component, maintain the same prop interface as the core component. This ensures compatibility with modules and other parts of the system.
Example - ProductCard props:
interface ProductCardProps {
product: {
id: string;
name: string;
slug: string;
price: string;
sale_price?: string;
images: Array<{ src: string; alt: string }>;
stock_status: string;
};
}The core theme uses Tailwind CSS v3. You can:
- Use Tailwind utilities directly in your components
- Extend Tailwind config in
tailwind.config.js - Override CSS variables in your global CSS
export default function CustomHeader() {
return (
<header className="bg-gradient-to-r from-blue-600 to-purple-600 text-white">
<h1 className="text-3xl font-bold">My Store</h1>
</header>
);
}You can use CSS modules if you prefer:
import styles from './Header.module.css';
export default function CustomHeader() {
return (
<header className={styles.header}>
<h1>My Store</h1>
</header>
);
}Child themes support any CSS approach:
- Styled Components
- Emotion
- Plain CSS
- CSS-in-JS
// theme-child/components/Header.tsx
import Link from "next/link";
export default function CustomHeader() {
return (
<header className="bg-gradient-to-r from-indigo-600 to-purple-600 text-white">
<div className="container mx-auto px-4 py-6">
<div className="flex items-center justify-between">
<h1 className="text-3xl font-bold">🛍️ My Store</h1>
<nav className="flex gap-6">
<Link href="/">Home</Link>
<Link href="/shop">Shop</Link>
<Link href="/cart">Cart</Link>
</nav>
</div>
</div>
</header>
);
}// theme-child/components/ProductCard.tsx
import Link from "next/link";
import { Price } from "@storefuse/theme-core"; // Reuse core components!
export default function CustomProductCard({ product }) {
return (
<Link href={`/product/${product.slug}`}>
<div className="border-2 border-purple-200 rounded-2xl p-4 hover:border-purple-500">
<img
src={product.images[0]?.src}
alt={product.name}
className="w-full rounded-lg"
/>
<h3 className="font-bold text-lg mt-4">{product.name}</h3>
<Price value={product.price} className="text-purple-600 text-xl" />
</div>
</Link>
);
}You can import and use core components in your child theme:
import { Button, Price, Badge } from "@storefuse/theme-core";
export default function CustomProductCard({ product }) {
return (
<div className="custom-card">
<Badge variant="sale">On Sale</Badge>
<h3>{product.name}</h3>
<Price value={product.price} />
<Button>Add to Cart</Button>
</div>
);
}// theme-child/index.ts
export const childThemeRegistry = {
Header: () => import("./components/Header"),
};// theme-child/index.ts
export const childThemeRegistry = {
Header: () => import("./components/Header"),
Footer: () => import("./components/Footer"),
ProductCard: () => import("./components/ProductCard"),
AddToCartButton: () => import("./components/AddToCartButton"),
};Don't copy all components. Only override the ones you want to customize. Everything else will use the core theme automatically.
❌ Don't do this:
// Copying every single component
export const childThemeRegistry = {
Header: () => import("./components/Header"),
Footer: () => import("./components/Footer"),
Navigation: () => import("./components/Navigation"),
Logo: () => import("./components/Logo"),
// ... 20 more components
};✅ Do this:
// Only override what you need
export const childThemeRegistry = {
Header: () => import("./components/Header"),
ProductCard: () => import("./components/ProductCard"),
};Keep the same prop interface as core components to ensure compatibility.
Get type safety by importing types from core:
import type { Product } from "@storefuse/core";
interface ProductCardProps {
product: Product;
}After updating @storefuse/theme-core, test your overridden components to ensure they still work.
Add comments explaining why you overrode a component:
/**
* Custom Header
*
* Overrides core Header to:
* - Add custom branding
* - Include mega menu
* - Add announcement bar
*/
export default function CustomHeader() {
// ...
}- Check that the component is registered in
index.ts - Restart your dev server
- Clear Next.js cache:
rm -rf .next
Import types from core packages:
import type { Product, Category } from "@storefuse/core";Make sure you've registered the component in your child theme registry and the file exists.
✅ Safe Updates - Core package updates won't overwrite your customizations
✅ No Merge Conflicts - Your files are separate from core
✅ Predictable Overrides - Simple registry-based resolution
✅ Works on Vercel - No filesystem magic, just module imports
✅ Type-Safe - Full TypeScript support
✅ Flexible Styling - Use Tailwind, CSS modules, or any CSS solution