Variation Selection Patterns
Explore different patterns for implementing variation selection, each with its own benefits for different use cases. Understand and implement the best variation selection pattern for your storefront's user experience needs.
Quick Start
Choose the right variation selection pattern for your storefront:
Pattern Overview
- Navigation-Based - Traditional approach with page reloads
- Dynamic State - Modern SPA approach with fast updates
- Hybrid - Best of both worlds
- Quick Shop Modal - For product listings
Choosing the Right Pattern
Pattern | Best For | SEO | Performance | Complexity |
---|---|---|---|---|
Navigation-Based | Traditional storefronts, SEO-critical sites | ✅ Excellent | ⚡ Slower | 🟢 Simple |
Dynamic State | SPAs, mobile apps | ❌ Limited | ⚡⚡⚡ Fast | 🟡 Moderate |
Hybrid | Modern storefronts wanting both | ✅ Good | ⚡⚡ Fast | 🔴 Complex |
Quick Shop Modal | Product listings, quick add | ❌ None | ⚡⚡⚡ Fast | 🟢 Simple |
Pattern 1: Navigation-Based Selection
Overview
Navigate to child product URLs as options are selected. This traditional approach reloads the page for each selection, making it ideal for SEO-critical sites and traditional storefronts.
When to Use
- SEO is critical for your business
- You need direct URLs to each variant
- Browser history navigation is important
- You're building a traditional e-commerce site
Key Characteristic
When all options are selected, navigate to the child product URL:
Implementation Focus
const router = useRouter();
const handleOptionSelect = (variationId: string, optionId: string) => {
const newOptions = {
...selectedOptions,
[variationId]: optionId
};
// Key difference: Navigate on selection
const childId = getSkuIdFromOptions(
Object.values(newOptions),
variationMatrix
);
if (childId && allOptionsSelected(newOptions)) {
router.replace(`/products/${childId}`);
}
};
Pros & Cons
✅ SEO-friendly URLs - Each variant has its own URL
✅ Direct links - Share specific variant URLs
✅ Browser navigation - Back/forward works naturally
✅ Simple implementation - Easy to understand and maintain
❌ Page refresh - Full reload on each selection
❌ Slower experience - Perceived performance is slower
Pattern 2: Dynamic State Management
Overview
Keep the parent URL and update the display dynamically based on selections. This modern approach provides instant feedback without page reloads, perfect for single-page applications and mobile apps.
When to Use
- Building a single-page application (SPA)
- Performance and user experience are priorities
- SEO for individual variants isn't critical
- You want to show real-time availability and pricing
Key Characteristic
Keep the URL static and update the displayed data dynamically:
Implementation Focus
const [selectedChild, setSelectedChild] = useState(null);
const handleOptionSelect = (variationId: string, optionId: string) => {
const newOptions = {
...selectedOptions,
[variationId]: optionId
};
// Key difference: Update state, not URL
const childId = getSkuIdFromOptions(
Object.values(newOptions),
variationMatrix
);
if (childId) {
const child = childProducts.find(p => p.id === childId);
setSelectedChild(child);
}
};
// Display dynamic data
const displayProduct = selectedChild || parentProduct;
return (
<>
<h1>{displayProduct.attributes.name}</h1>
<p>SKU: {displayProduct.attributes.sku || 'Select options'}</p>
<p>Price: ${displayProduct.attributes.price?.[0]?.amount / 100}</p>
<button
disabled={!selectedChild}
onClick={() => addToCart(selectedChild.id)}
>
{selectedChild ? 'Add to Cart' : 'Select All Options'}
</button>
</>
);
Pros & Cons
✅ Fast updates - No page reloads
✅ Smooth UX - Instant feedback on selections
✅ Show availability - Real-time stock updates
✅ Flexible display - Show/hide unavailable options
❌ No variant URLs - Can't share specific variants
❌ Complex state - More state management required
Pattern 3: Hybrid Approach
Overview
Combine the best of both worlds by updating URLs without full page reloads. This approach provides SEO benefits while maintaining a smooth user experience, ideal for modern storefronts.
When to Use
- You need both SEO and performance
- Building a modern e-commerce site
- Want shareable URLs without page reloads
- Using a framework that supports client-side routing
Key Characteristic
Update the URL without page reload while fetching new data:
Implementation Focus
const [isTransitioning, setIsTransitioning] = useState(false);
const handleOptionSelect = async (variationId: string, optionId: string) => {
const newOptions = { ...selectedOptions, [variationId]: optionId };
if (!allOptionsSelected(newOptions)) return;
const childId = getSkuIdFromOptions(
Object.values(newOptions),
variationMatrix
);
if (childId) {
setIsTransitioning(true);
// Key differences:
// 1. Update URL without reload
window.history.pushState({}, '', `/products/${childId}`);
// 2. Fetch child data via API
const response = await getByContextProduct({
path: { product_id: childId }
});
// 3. Update displayed product
setProduct(response.data);
setIsTransitioning(false);
}
};
// 4. Handle browser back/forward
useEffect(() => {
const handlePopState = async () => {
const productId = window.location.pathname.split('/').pop();
if (productId !== product.id) {
// Re-fetch when user navigates
const response = await getByContextProduct({
path: { product_id: productId }
});
setProduct(response.data);
}
};
window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, [product.id]);
Pros & Cons
✅ SEO-friendly - Maintains unique URLs
✅ Fast UX - No full page reloads
✅ Browser history - Back/forward navigation works
✅ Modern approach - Best of both patterns
❌ Complex implementation - Most difficult to build
❌ State synchronization - URL and UI must stay in sync
Pattern 4: Quick Shop Modal
Overview
Perfect for product listing pages where shoppers can quickly select variations and add to cart without leaving the list. This pattern enhances the shopping experience by reducing navigation.
When to Use
- Product listing pages or category pages
- Quick add-to-cart functionality
- Mobile shopping experiences
- When browsing flow is more important than deep product details
Key Characteristic
Show variation selection in a modal without leaving the product list:
Implementation Focus
// In product listing
function ProductCard({ product }) {
const [showQuickShop, setShowQuickShop] = useState(false);
return (
<div className="product-card">
<img src={product.attributes.main_image} />
<h3>{product.attributes.name}</h3>
<button onClick={() => setShowQuickShop(true)}>
Quick Shop
</button>
{showQuickShop && (
<QuickShopModal
parentProductId={product.id}
onClose={() => setShowQuickShop(false)}
onAddToCart={(childId) => {
addToCart(childId);
setShowQuickShop(false);
}}
/>
)}
</div>
);
}
// Simplified modal logic
function QuickShopModal({ parentProductId, onClose, onAddToCart }) {
const [selectedChild, setSelectedChild] = useState(null);
// Key differences:
// 1. Load parent only when modal opens
useEffect(() => {
if (parentProductId) {
loadParentProduct(parentProductId);
}
}, [parentProductId]);
// 2. Handle selection in modal context
const handleOptionSelect = (variationId, optionId) => {
// Same selection logic, but in modal
const childId = getSkuIdFromOptions(...);
setSelectedChild(childId);
};
// 3. Add to cart without navigation
const handleAddToCart = () => {
if (selectedChild) {
onAddToCart(selectedChild);
}
};
return (
<Modal isOpen onClose={onClose}>
{/* Variation selectors */}
<button
onClick={handleAddToCart}
disabled={!selectedChild}
>
Add to Cart
</button>
</Modal>
);
}
Pros & Cons
✅ Quick shopping - Add to cart without leaving list
✅ Maintains context - Stay on category page
✅ Mobile-friendly - Works great on small screens
✅ Reduces navigation - Fewer page loads
❌ No product URLs - Can't share specific variants
❌ Limited space - Less room for product details
Summary
Each pattern solves different needs:\n- Navigation: SEO and shareable URLs\n- Dynamic: Fast, smooth experience\n- Hybrid: Balance of both\n- Quick Shop: Minimal friction
Key Takeaways
- Choose the Right Pattern: Use the decision flowchart to select the best pattern for your needs
- Consider Your Users: Different patterns suit different shopping behaviors
- Test Performance: Measure actual performance in your environment
- Plan for Mobile: Ensure your pattern works well on all devices
- Handle Edge Cases: Plan for invalid combinations and loading states
Next Steps
- Understanding the Variation Matrix - Deep dive into the variation matrix structure
- List Parent & Child Products - Learn to fetch and display product variations
- Select a Variation - Step-by-step guide to building a variation selector