Skip to main content

VariantSelector

Description

Displays product variant options (size, color, etc.) with automatic availability detection. Updates URL and page data when options are selected. Supports custom rendering for attributes and options.

Import

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';

Usage

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';
import { ProductProvider } from '@components/frontStore/catalog/ProductContext';
import { FormProvider, useForm } from 'react-hook-form';

function ProductPage({ product }) {
const methods = useForm();

return (
<ProductProvider product={product}>
<FormProvider {...methods}>
<VariantSelector />
</FormProvider>
</ProductProvider>
);
}

Props

NameTypeRequiredDescription
AttributeRendererReact.ComponentTypeNoCustom attribute group renderer
OptionRendererReact.ComponentTypeNoCustom option item renderer

Type Definitions

ProcessedAttribute

interface ProcessedAttribute {
attributeId: number;
attributeCode: string;
attributeName: string;
options: Array<{
optionId: number;
optionText: string;
available: boolean; // Can be selected with current selections
}>;
selected: boolean;
selectedOption: number | null;
}

Custom Renderer Props

AttributeRenderer Props

interface VariantAttributeGroupProps {
attribute: ProcessedAttribute;
options: Array<AttributeOption & { available: boolean }>;
onSelect: (attributeCode: string, optionId: number) => Promise<void>;
OptionItem?: React.ComponentType<VariantOptionItemProps>;
}

OptionRenderer Props

interface VariantOptionItemProps {
option: AttributeOption & { available: boolean };
attribute: ProcessedAttribute;
isSelected: boolean;
onSelect: (attributeCode: string, optionId: number) => Promise<void>;
}

Examples

Basic Usage

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';
import { ProductProvider } from '@components/frontStore/catalog/ProductContext';
import { FormProvider, useForm } from 'react-hook-form';

function ProductDetail({ product }) {
const methods = useForm();

return (
<ProductProvider product={product}>
<FormProvider {...methods}>
<div className="product-options">
<VariantSelector />
</div>
</FormProvider>
</ProductProvider>
);
}

Custom Option Renderer

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';

function CustomOptionItem({ option, isSelected, onSelect, attribute }) {
return (
<button
onClick={() => onSelect(attribute.attributeCode, option.optionId)}
disabled={!option.available}
className={`
option-btn
${isSelected ? 'selected' : ''}
${!option.available ? 'disabled' : ''}
`}
>
{option.optionText}
{!option.available && <span className="unavailable-badge">×</span>}
</button>
);
}

function ProductVariants() {
return <VariantSelector OptionRenderer={CustomOptionItem} />;
}

Custom Attribute Renderer

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';

function CustomAttributeGroup({ attribute, options, onSelect, OptionItem }) {
return (
<div className="variant-group">
<h3 className="attribute-name">
{attribute.attributeName}
{attribute.selected && <span className="checkmark"></span>}
</h3>
<div className="options-grid">
{options.map(option => (
<OptionItem
key={option.optionId}
option={option}
attribute={attribute}
isSelected={attribute.selectedOption === option.optionId}
onSelect={onSelect}
/>
))}
</div>
</div>
);
}

function ProductVariants() {
return <VariantSelector AttributeRenderer={CustomAttributeGroup} />;
}

Color Swatches

import { VariantSelector } from '@components/frontStore/catalog/VariantSelector';

function ColorSwatch({ option, isSelected, onSelect, attribute }) {
// Assuming option has a color hex value
const colorCode = option.colorCode || '#ccc';

return (
<button
onClick={() => onSelect(attribute.attributeCode, option.optionId)}
disabled={!option.available}
className={`
color-swatch
${isSelected ? 'ring-2 ring-blue-500' : ''}
${!option.available ? 'opacity-30 cursor-not-allowed' : ''}
`}
style={{ backgroundColor: colorCode }}
title={option.optionText}
>
{isSelected && <span className="checkmark"></span>}
</button>
);
}

function ProductPage() {
return (
<VariantSelector
OptionRenderer={ColorSwatch}
/>
);
}