Select Product Variants in Storefront

In this document, you'll learn how to select a product variant to be added to the cart in the storefront.

NoteThe add-to-cart functionality is explained in the Cart's guides.

If a product has different options and variants for those options, the customer has to choose the options when adding the product to the cart.

Since a variant is a combination of the product options' values (for example, size S and color Blue), you find the variant based on the chosen option values.

For example, in a React-based storefront:

Code
1"use client" // include with Next.js 13+2
3import { useEffect, useMemo, useState } from "react"4import { HttpTypes } from "@medusajs/types"5
6type Props = {7  id: string8}9
10export default function Product({ id }: Props) {11  const [loading, setLoading] = useState(true)12  const [product, setProduct] = useState<13    HttpTypes.StoreProduct | undefined14  >()15  const [selectedOptions, setSelectedOptions] = useState<Record<string, string>>({})16
17  useEffect(() => {18    if (!loading) {19      return 20    }21
22    fetch(`http://localhost:9000/store/products/${id}`, {23      credentials: "include",24      headers: {25        "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",26      },27    })28    .then((res) => res.json())29    .then(({ product: dataProduct }) => {30      setProduct(dataProduct)31      setLoading(false)32    })33  }, [loading])34
35  const selectedVariant = useMemo(() => {36    if (37      !product?.variants ||38      !product.options || 39      Object.keys(selectedOptions).length !== product.options?.length40    ) {41      return42    }43
44    return product.variants.find((variant) => variant.options?.every(45      (optionValue) => optionValue.id === selectedOptions[optionValue.option_id!]46    ))47  }, [selectedOptions, product])48
49  return (50    <div>51      {loading && <span>Loading...</span>}52      {product && (53        <>54          <h1>{product.title}</h1>55          {(product.options?.length || 0) > 0 && (56            <ul>57              {product.options!.map((option) => (58                <li key={option.id}>59                  {option.title}60                  {option.values?.map((optionValue) => (61                    <button 62                      key={optionValue.id}63                      onClick={() => {64                        setSelectedOptions((prev) => {65                          return {66                            ...prev,67                            [option.id!]: optionValue.value!,68                          }69                        })70                      }}71                    >72                      {optionValue.value}73                    </button>74                  ))}75                </li>76              ))}77            </ul>78          )}79          {selectedVariant && (80            <span>Selected Variant: {selectedVariant.id}</span>81          )}82          {product.images?.map((image) => (83            <img src={image.url} key={image.id} />84          ))}85        </>86      )}87    </div>88  )89}

In this example, you:

  • Store the selected options in the selectedOptions state variable. It's an object whose keys are options' ID, and values are the selected value of that option.
  • Compute the selected variable whenever the selected option is changed. When the customer chooses a value for all options, you find a product variant that has the same chosen option-value combinations.
  • Change the selectedOptions's value whenever the customer clicks on an option value.
  • Show the ID of the selected variant when it's found.
Was this page helpful?
Edit this page
Ask Anything
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break