Understanding the Variation Matrix
Learn how to work with Elastic Path's variation matrix, a powerful nested structure that maps product options to child product IDs. Master the matrix structure and implement robust product selection logic that handles any number of variations.
Understanding the Structure
The variation matrix uses option IDs (not variation IDs) as keys. The structure depth depends on how many variations your product has:
Here's a real variation matrix structure:
{
"801eabad-5108-4991-9f98-1830252214eb": { // Black leather option ID
"8f749ee2-17fb-4876-963f-2f57c0dffd97": "ed971d72-ca0c-4472-86f9-db03227bebfd", // Small
"d536955b-afa3-40e4-88cc-f6ee0248eeea": "ca9791a6-5adb-4207-8ea3-5a5b3d58fc4f", // Medium
"bbd91e51-690b-4743-9eb7-185a5bb88a62": "86ffccbe-6dfa-4903-9861-27eaef046761", // Large
"a987256b-76d1-4dad-b59e-fcc1c6198d1f": "9df52c2e-a145-4ee5-9abe-2d2961fadd2d" // XL
},
"84fd8ba0-9829-4b79-bfe9-ffee1ab60b95": { // Chestnut leather option ID
"8f749ee2-17fb-4876-963f-2f57c0dffd97": "7ed766a9-7e1c-4fce-bfed-0455bf4c3af0", // Small
// ... more size options
}
// ... more color options
}
Key Concepts
- Option IDs as Keys: The matrix uses option IDs directly, not variation IDs
- Nesting Order: Determined by how variations were configured (often alphabetical or creation order)
- Flexible Depth: 2 levels for 2 variations, 3 levels for 3 variations, etc.
- No Fixed Pattern: The first level could be Size or Color depending on your product setup
Implementation Approach: Recursive Lookup
The most flexible approach is to use a recursive function that can handle any depth of nesting:
// Recursive function used by Elastic Path's Composable Frontend
export function getSkuIdFromOptions(
options: string[],
matrix: any
): string | undefined {
// Base case: if we've reached a child product ID (string)
if (typeof matrix === 'string') {
return matrix;
}
// Try each option as a key in the current matrix level
for (const currOption in options) {
const optionId = options[currOption];
const nestedMatrix = matrix[optionId];
if (nestedMatrix) {
// Recurse deeper into the matrix
return getSkuIdFromOptions(options, nestedMatrix);
}
}
return undefined;
}
// Usage example
const selectedOptions = [
'801eabad-5108-4991-9f98-1830252214eb', // Black leather
'8f749ee2-17fb-4876-963f-2f57c0dffd97' // Small size
];
const childProductId = getSkuIdFromOptions(selectedOptions, variationMatrix);
// Returns: 'ed971d72-ca0c-4472-86f9-db03227bebfd'
Why Use Recursive Lookup?
- Handles Any Number of Variations: Works with 1, 2, 3+ variations without modification
- Order Agnostic: Doesn't need to know which variation is at which level
- Future Proof: Adapts to changes in how variations are structured
- Production Tested: Used in Elastic Path's official example implementation
Alternative: Direct Lookup (When You Know the Structure)
If you know your matrix structure is always consistent (e.g., Color → Size), you can use direct lookup:
// Direct lookup when you know the structure
function getChildDirectly(
colorOptionId: string,
sizeOptionId: string,
matrix: any
): string | undefined {
return matrix[colorOptionId]?.[sizeOptionId];
}
// Much simpler, but less flexible
const childId = getChildDirectly(
'801eabad-5108-4991-9f98-1830252214eb', // Black
'8f749ee2-17fb-4876-963f-2f57c0dffd97', // Small
variationMatrix
);
Complete Example: From Selection to Cart
Here's a full implementation showing how to use the recursive lookup:
import { getSkuIdFromOptions } from '@/utils/product-helper';
// Parent product with variations
const parentProduct = {
id: "a2c20cd6-5f34-47b6-9582-5044a5b50991",
meta: {
variations: [
{
id: "10a35688-d48e-4228-8bd2-b3b5f71c992d",
name: "Couch Size",
options: [
{ id: "8f749ee2-17fb-4876-963f-2f57c0dffd97", name: "Small" },
{ id: "d536955b-afa3-40e4-88cc-f6ee0248eeea", name: "Medium" }
]
},
{
id: "6cc91048-c351-4b35-aacd-8d613d515fa7",
name: "Leather Color",
options: [
{ id: "801eabad-5108-4991-9f98-1830252214eb", name: "Black" },
{ id: "84fd8ba0-9829-4b79-bfe9-ffee1ab60b95", name: "Chestnut" }
]
}
],
variation_matrix: {
"801eabad-5108-4991-9f98-1830252214eb": { // Black
"8f749ee2-17fb-4876-963f-2f57c0dffd97": "ed971d72-ca0c-4472-86f9-db03227bebfd", // Small
"d536955b-afa3-40e4-88cc-f6ee0248eeea": "ca9791a6-5adb-4207-8ea3-5a5b3d58fc4f" // Medium
},
"84fd8ba0-9829-4b79-bfe9-ffee1ab60b95": { // Chestnut
"8f749ee2-17fb-4876-963f-2f57c0dffd97": "7ed766a9-7e1c-4fce-bfed-0455bf4c3af0", // Small
"d536955b-afa3-40e4-88cc-f6ee0248eeea": "1478ea17-078c-4e3c-b3b0-d8400823a3ba" // Medium
}
}
}
};
// Component implementation
function VariationSelector({ parentProduct, onAddToCart }) {
const [selectedOptions, setSelectedOptions] = useState({});
const handleOptionSelect = (variationId: string, optionId: string) => {
setSelectedOptions(prev => ({
...prev,
[variationId]: optionId
}));
};
const handleAddToCart = () => {
// Get selected option IDs as an array
const optionIds = Object.values(selectedOptions);
// Use recursive lookup
const childId = getSkuIdFromOptions(
optionIds,
parentProduct.meta.variation_matrix
);
if (childId) {
onAddToCart(childId);
}
};
// Check if all variations have selections
const allSelected = parentProduct.meta.variations.every(
v => selectedOptions[v.id] !== undefined
);
return (
<div>
{/* Render variation options */}
{parentProduct.meta.variations.map(variation => (
<VariationOptions
key={variation.id}
variation={variation}
selectedId={selectedOptions[variation.id]}
onSelect={(optionId) => handleOptionSelect(variation.id, optionId)}
/>
))}
<button
disabled={!allSelected}
onClick={handleAddToCart}
>
Add to Cart
</button>
</div>
);
}
Key Takeaways
Understanding the Variation Matrix
- Structure: The matrix uses option IDs as keys, not variation IDs
- Nesting Order: Determined by product configuration, not predictable
- Depth: Equals the number of variations (2 variations = 2 levels deep)
- Values: The leaf nodes are always child product UUIDs
Best Practices
- Use Recursive Lookup: The
getSkuIdFromOptions
function handles any variation structure - Don't Assume Order: The matrix structure can vary between products
- Validate Selections: Ensure all variations have selections before lookup
- Handle Edge Cases: Check for undefined results and provide user feedback
Common Pitfalls to Avoid
- Don't hardcode matrix structure - It varies by product
- Don't assume which variation is at which level - Use recursive lookup
- Don't forget to handle products with 1 or 3+ variations
- Don't mix up variation IDs with option IDs - The matrix uses option IDs
Next Steps
- Variation Selection Patterns - Different UI patterns for implementing variation selection
- Select a Variation - Step-by-step guide to building a variation selector