variant-selection

📁 saleor/storefront 📅 7 days ago
3
总安装量
3
周安装量
#58783
全站排名
安装命令
npx skills add https://github.com/saleor/storefront --skill variant-selection

Agent 安装分布

amp 3
github-copilot 3
codex 3
kimi-cli 3
gemini-cli 3
cursor 3

Skill 文档

Variant Selection System

Source: Saleor Docs – Attributes – How product/variant attributes work

When to Use

Use this skill when:

  • Modifying variant/attribute selection on product pages
  • Understanding why a variant isn’t selectable
  • Adding discount indicators to variant options
  • Debugging “Add to Cart” button state

Instructions

Core Concept: Variants, Not Products

You add VARIANTS to cart, not products. Each variant is a specific attribute combination:

Product Attributes Variant ID
T-Shirt Black + Medium abc123
T-Shirt Black + Large def456
T-Shirt White + Medium ghi789

The checkoutLinesAdd mutation requires a specific variantId. Without selecting ALL attributes, there’s no variant to add.

Two Types of Variant Attributes

Saleor distinguishes between two types of variant attributes:

Type variantSelection Purpose UI Passed to Cart?
Selection VARIANT_SELECTION Identify which variant (color, size) Interactive picker No – just the variantId
Non-Selection NOT_VARIANT_SELECTION Describe the variant (material, brand) Display-only badges No – already on variant

Key insight: Neither type is “passed” to checkout. You only pass the variantId. All attributes are already stored on the variant in Saleor.

# GraphQL queries use the variantSelection filter:
selectionAttributes: attributes(variantSelection: VARIANT_SELECTION) { ... }
nonSelectionAttributes: attributes(variantSelection: NOT_VARIANT_SELECTION) { ... }

Non-selection attributes are display-only – shown as informational badges, not interactive selectors.

File Structure

src/ui/components/pdp/variant-selection/
├── index.ts                      # Public exports
├── types.ts                      # TypeScript interfaces
├── utils.ts                      # Data transformation & logic
├── variant-selector.tsx          # Single attribute selector
├── variant-selection-section.tsx # Main container
├── optional-attributes.tsx       # Non-selection attribute badges
└── renderers/
    ├── color-swatch-option.tsx   # Color swatch (circular)
    └── button-option.tsx         # Button for size/text (unified)

Key Functions in utils.ts

Function Purpose
groupVariantsByAttributes() Extract unique attribute values from variants
findMatchingVariant() Find variant matching ALL selected attributes
getOptionsForAttribute() Get options with availability/compatibility info
getAdjustedSelections() Clear conflicting selections when needed
getUnavailableAttributeInfo() Detect dead-end selections

For detailed function signatures and usage, see UTILS_REFERENCE.md.

Option States

State Meaning Visual Clickable?
Available In stock Normal ✓
Incompatible No variant with this + current selections Dimmed ✓ (clears others)
Out of stock Variant exists but quantity = 0 Strikethrough ✗

URL Parameter Pattern

Selections are stored in URL params:

?color=black&size=m&variant=abc123
  ↑           ↑       ↑
Color sel  Size sel  Matching variant (set automatically)

The variant param is only set when ALL attributes are selected.

Discount Badges

Options can show discount percentages:

// In utils.ts
interface VariantOption {
	id: string;
	name: string;
	available: boolean;
	hasDiscount?: boolean; // Any variant with this option is discounted
	discountPercent?: number; // Max discount percentage
	// ...
}

The renderers display a small badge when discountPercent is set.

Examples

Smart Selection Adjustment

When user selects an incompatible option:

State: ?color=red (Red only exists in Size S)
User clicks: Size L
Result: ?size=l (Red is cleared, not blocked)

Users are never “stuck” – they can always explore all options.

Dead End Detection

const deadEnd = getUnavailableAttributeInfo(variants, groups, selections);
// Returns: { slug: "size", name: "Size", blockedBy: "Red" }
// UI shows: "No size available in Red"

Custom Renderers

<VariantSelectionSection
	variants={variants}
	renderers={{
		color: MyCustomColorPicker,
		size: MySizeChart,
	}}
/>

State Machine

The selection system has 5 states with automatic conflict resolution. For the full state diagram and transition rules, see STATE_MACHINE.md.

Quick reference:

State Add to Cart Description
Empty ❌ No selections
Partial ❌ Some attributes selected
Complete ✅ All selected, variant found
Conflict — Auto-clears to Partial
DeadEnd ❌ Selection blocks other groups

Key behavior: When user selects an incompatible option, other selections are cleared automatically (not blocked). Users can always explore all options.

Anti-patterns

❌ Don’t enable “Add to Cart” without full selection – Needs variant ID
❌ Don’t block incompatible options – Let users click, clear others
❌ Don’t assume single attribute – Products can have multiple
❌ Don’t use 0 in boolean checks for prices – Use typeof === "number"
❌ Don’t make non-selection attributes interactive – They’re display-only (badges, not toggles)