Skip to main content

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

  1. Navigation-Based - Traditional approach with page reloads
  2. Dynamic State - Modern SPA approach with fast updates
  3. Hybrid - Best of both worlds
  4. Quick Shop Modal - For product listings

Choosing the Right Pattern

PatternBest ForSEOPerformanceComplexity
Navigation-BasedTraditional storefronts, SEO-critical sites✅ Excellent⚡ Slower🟢 Simple
Dynamic StateSPAs, mobile apps❌ Limited⚡⚡⚡ Fast🟡 Moderate
HybridModern storefronts wanting both✅ Good⚡⚡ Fast🔴 Complex
Quick Shop ModalProduct 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

  1. Choose the Right Pattern: Use the decision flowchart to select the best pattern for your needs
  2. Consider Your Users: Different patterns suit different shopping behaviors
  3. Test Performance: Measure actual performance in your environment
  4. Plan for Mobile: Ensure your pattern works well on all devices
  5. Handle Edge Cases: Plan for invalid combinations and loading states

Next Steps

References