Variants, Attributes and Live Pricing
A Vue product configurator for configurable Magento products must keep attributes, variants, price and availability in sync, without triggering a full page reload on every selection. With the right data structure this works with a single initial load request.
Table of Contents
- 1. What a Vue product configurator must handle
- 2. Data model: attributes, variants and SKU resolution
- 3. Modeling configurator state in a composable
- 4. Loading configurable products from Magento GraphQL
- 5. Live pricing on attribute selection
- 6. Keeping the gallery in sync with the selection
- 7. Handling availability and disabled options
- 8. Validation and error states in the configurator
- 9. Product configurator compared: approaches
- 10. Summary
- 11. FAQ
1. What a Vue product configurator must handle
A Vue product configurator for configurable Magento products, for example a T-shirt in several colors and sizes, must keep four things in sync at once: the selected attribute values, the resulting variant SKU, the current price and availability. If the user changes the color, the available size options may also need to adjust, the product image may need to change, and the price may need to be recalculated, all without a visible loading state.
The most common mistake with a self-built Vue product configurator: a separate GraphQL request is sent to Magento for every attribute combination. For a product with five colors and six sizes, that is theoretically thirty possible requests just to find out which combination exists. The better approach loads the complete variant matrix once on page load and resolves every selection purely on the client afterward.
The following sections build a Vue product configurator step by step: from the data model through the GraphQL integration to live pricing and handling unavailable combinations.
2. Data model: attributes, variants and SKU resolution
Magento delivers configurable products through GraphQL as configurable_options and variants. Each variant contains its own SKU, its own price and the combination of attribute values it represents. For a performant Vue product configurator, it pays off to transform this raw structure into a lookup map whose key is a sorted combination of the selected attribute values, for example color:red|size:m, and whose value is the matching variant.
This lookup map turns SKU resolution in the Vue product configurator into a single object access operation instead of a loop over all variants on every selection. For products with several hundred variants, as is common with furniture with many material options, this difference makes the configurator noticeably more responsive.
// composables/useVariantMatrix.ts — build a fast lookup map from Magento variants
interface MagentoVariant {
product: { sku: string; price_range: { minimum_price: { final_price: { value: number } } } };
attributes: { code: string; value_index: number }[];
}
function buildVariantKey(attributes: { code: string; value_index: number }[]): string {
return attributes
.slice()
.sort((a, b) => a.code.localeCompare(b.code))
.map((a) => `${a.code}:${a.value_index}`)
.join('|');
}
export function useVariantMatrix(variants: MagentoVariant[]) {
const matrix = new Map<string, MagentoVariant>();
for (const variant of variants) {
matrix.set(buildVariantKey(variant.attributes), variant);
}
function resolve(selection: Record<string, number>): MagentoVariant | undefined {
const key = buildVariantKey(
Object.entries(selection).map(([code, value_index]) => ({ code, value_index }))
);
return matrix.get(key);
}
return { matrix, resolve };
}
3. Modeling configurator state in a composable
The central state of a Vue product configurator is the current selection per attribute, a simple reactive object like { color: null, size: null }. All derived values, variant SKU, price, image and availability, are computed from this state via computed properties, never synchronized manually. This prevents the classic bug class where price and selection drift apart because an update path was forgotten.
A useProductConfigurator composable encapsulates this state together with the variant matrix from section two and only exposes the reactive values the component actually needs. The component itself stays lean and contains no calculation logic, only bindings to the composable. For tests, the composable can be checked in isolation without a rendered component, which noticeably simplifies test coverage of the Vue product configurator.
// composables/useProductConfigurator.ts — central configurator state
import { reactive, computed } from 'vue';
import { useVariantMatrix } from './useVariantMatrix';
export function useProductConfigurator(product: MagentoConfigurableProduct) {
const { resolve } = useVariantMatrix(product.variants);
const selection = reactive<Record<string, number | null>>(
Object.fromEntries(product.configurable_options.map((o) => [o.attribute_code, null]))
);
const isComplete = computed(() => Object.values(selection).every((v) => v !== null));
const activeVariant = computed(() => {
if (!isComplete.value) return undefined;
return resolve(selection as Record<string, number>);
});
const currentPrice = computed(() => {
return activeVariant.value?.product.price_range.minimum_price.final_price.value
?? product.price_range.minimum_price.final_price.value;
});
function selectAttribute(code: string, valueIndex: number) {
selection[code] = valueIndex;
}
return { selection, isComplete, activeVariant, currentPrice, selectAttribute };
}
4. Loading configurable products from Magento GraphQL
For a Vue product configurator, it is critical to load both configurable_options and all variants with their price, image and stock in a single GraphQL query. If the query is cut too narrow, additional follow-up requests will appear during use, briefly freezing the configurator on every selection. If it is cut too broad, initial load time grows unnecessarily for products with many variants.
A good middle ground for the Vue product configurator: the query loads price and SKU for every variant, but images only in a low-resolution preview version, with the full gallery loaded only after the selection is completed for the specific variant. That keeps the initial payload small without needing a second request for price calculation.
// graphql/queries/configurableProduct.ts — single query for options, variants and pricing
export const CONFIGURABLE_PRODUCT_QUERY = `
query getConfigurableProduct($sku: String!) {
products(filter: { sku: { eq: $sku } }) {
items {
sku
name
price_range { minimum_price { final_price { value currency } } }
... on ConfigurableProduct {
configurable_options {
attribute_code
label
values { value_index label }
}
variants {
attributes { code value_index }
product {
sku
stock_status
price_range { minimum_price { final_price { value currency } } }
image { url(width: 240) label }
}
}
}
}
}
}
`;
5. Live pricing on attribute selection
Live pricing in the Vue product configurator must never wait for another network request, or every attribute selection will feel sluggish. Since the complete variant matrix already sits in memory from section four, price calculation is a pure computed derivation, as shown in the composable in section three. When the user changes the color, the displayed price updates within the same render cycle, without noticeable delay.
For products with surcharges per attribute value, for example a more expensive material upgrade, the plain variant price sometimes is not enough. The Vue product configurator must then add base price and attribute surcharges instead of blindly relying on the variant's final price. A test suite with concrete price fixtures for every attribute combination prevents rounding errors or incorrectly applied discounts from sneaking in unnoticed.
6. Keeping the gallery in sync with the selection
Once a variant is fully selected in the Vue product configurator, the product gallery should automatically switch to the images matching that variant, for example the red instead of the blue T-shirt. A watch on the activeVariant from the composable triggers this switch, without the gallery component itself needing to know how variants are resolved.
A smooth transition matters more than a hard image jump, especially when a selection is temporarily incomplete, for example after choosing a color but before choosing a size. In this state, the Vue product configurator sensibly shows the main image of the chosen color across all sizes, not the product's generic default image.
// components/ProductConfigurator.vue — sync gallery with variant selection
watch(activeVariant, (variant) => {
if (variant?.product.image?.url) {
galleryImage.value = variant.product.image.url;
return;
}
// Fallback: show the image of the color-only match, ignore size
const colorOnlyVariant = variants.find(
(v) => v.attributes.some((a) => a.code === 'color' && a.value_index === selection.color)
);
galleryImage.value = colorOnlyVariant?.product.image?.url ?? baseProductImage.value;
});
7. Handling availability and disabled options
Not every attribute combination exists as a variant. A Vue product configurator therefore needs to show, even before the selection is complete, which remaining options actually still lead to an existing, in-stock variant. In practice this means: once a color is selected, sizes for which no variant exists in that color, or whose stock is zero, get disabled in the selection instead of being removed.
Disabling instead of removing is the better UX decision for a Vue product configurator, because the user sees that the size fundamentally exists but is currently unavailable in this color. This prevents confusion compared to a list whose length changes on every selection. Calculating which values get disabled is a filtering of the variant matrix against the already made partial selection.
8. Validation and error states in the configurator
A Vue product configurator should only enable the add-to-cart button once isComplete from the composable is true and the resolved variant is actually in stock. A common mistake is enabling the button based purely on attribute completeness without checking the specific variant's stock, leading to error messages only appearing after clicking add to cart, instead of being visible beforehand.
For edge cases like temporarily sold-out variants, the Vue product configurator should show a clear inline message next to the affected option, for example temporarily unavailable, instead of confronting the user with a generic error message only after the full selection. This early, contextual error communication noticeably reduces support requests and cart abandonment.
9. Product configurator compared: approaches
There are different strategies for how a Vue product configurator can resolve variants. The following table compares the common approaches by loading behavior and complexity.
| Approach | Network requests | Response time | When it makes sense |
|---|---|---|---|
| Request per selection | Many | Noticeably delayed | Not recommended beyond a handful of variants |
| Full matrix upfront | One | Instant | Standard for most configurable products |
| Paginated matrix | Few | Short delay | Extremely large variant counts, over 500 |
| Server-computed price | One per selection | Network-dependent | Complex, personalized B2B pricing logic |
For the vast majority of Magento shops with configurable products, the full matrix upfront is the right choice for a Vue product configurator, because it enables instant response without increasing server load through repeated requests. Only for extremely large variant counts or highly complex personalized pricing logic does the extra effort of a server-side calculation pay off.
Mironsoft
Vue product configurators for configurable Magento products
A product configurator that responds instantly to every selection?
We build Vue product configurators with a variant matrix, live pricing and clean availability logic, without unnecessary follow-up requests on every attribute selection.
Configurator build
Design variant matrix, composables and GraphQL query from the ground up
Performance optimization
Audit existing configurators for unnecessary network requests and optimize them
UX polish
Design availability logic, error states and gallery sync for a friendly experience
10. Summary
A production-ready Vue product configurator loads the complete variant matrix of configurable Magento products in a single GraphQL request and then resolves every attribute selection purely on the client through a lookup map. Price, image and availability are calculated as computed derivations from the central selection state, never synchronized manually, which prevents the classic bug class of drifting states.
Disabled instead of removed options communicate availability more clearly, and early, contextual error messages instead of generic cart errors reduce cart abandonment. For the vast majority of configurable products, the full matrix upfront is the right approach, only for extreme variant counts or complex B2B pricing logic does a server-side calculation per selection pay off in the Vue product configurator.
Vue Product Configurator: The Key Takeaways
Data model
Variant matrix as a lookup map, keys from sorted attribute values, one request instead of many.
State management
Selection state plus computed derivations for price, image and availability in the composable.
UX
Disabled instead of removed options, smooth gallery transitions, early error communication.
Performance
One initial GraphQL request, then purely client-side resolution without network latency.