Example: Show Product Variant's Price

In this guide, you'll learn how to display a product variant's price with a full React example.

Tip: 

This guide doesn't take into account sale or tax prices. Refer to the following guides to learn how to show them:

Price Formatting#

To format a price, use JavaScript's NumberFormat utility. You pass it the amount and the currency code (which you retrieve from the selected region):

Tip: Refer to the Store Selected Region guide to learn how to store and retrieve the selected region's currency code.
Code
1const formatPrice = (amount: number): string => {2  return new Intl.NumberFormat("en-US", {3    style: "currency",4    currency: region.currency_code,5  })6  .format(amount)7}

You'll use this function to format prices in your storefront, including the selected variant's price.


Display Selected Variant Price#

Once the customer selects a variant (as explained in the Select Product Variants guide), use its calculated_price.calculated_amount property to display its price:

Code
1const price = formatPrice(2  selectedVariantPrice.calculated_price.calculated_amount3)

The price variable holds the formatted price of the selected variant with the currency of the selected region.

Tip: Learn about the calculated_price field in the Retrieve Product Variant's Prices section.

Full React Example#

The following React-based storefront example retrieves the product's price based on the selected variant:

Tip: 
Code
1"use client" // include with Next.js 13+2
3import { useEffect, useMemo, useState } from "react"4import { HttpTypes } from "@medusajs/types"5import { useRegion } from "@/providers/region"6import { sdk } from "@/lib/sdk"7
8type Props = {9  id: string10}11
12export default function Product({ id }: Props) {13  const [loading, setLoading] = useState(true)14  const [product, setProduct] = useState<15    HttpTypes.StoreProduct | undefined16  >()17  const [selectedOptions, setSelectedOptions] = useState<Record<string, string>>({})18  const { region } = useRegion()19
20  useEffect(() => {21    if (!loading) {22      return 23    }24
25    sdk.store.product.retrieve(id, {26      fields: `*variants.calculated_price`,27      region_id: region.id,28    })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.value === selectedOptions[optionValue.option_id!]46    ))47  }, [selectedOptions, product])48
49  const formatPrice = (amount: number): string => {50    return new Intl.NumberFormat("en-US", {51      style: "currency",52      currency: region.currency_code,53    })54    .format(amount)55  }56
57  const selectedVariantPrice = useMemo(() => {58    if (selectedVariant) {59      return selectedVariant60    }61
62    return product?.variants?.sort((a: any, b: any) => {63      return (64        a.calculated_price.calculated_amount -65        b.calculated_price.calculated_amount66      )67    })[0]68  }, [selectedVariant, product])69
70  const price = useMemo(() => {71    if (!selectedVariantPrice) {72      return73    }74
75    // @ts-ignore76    return formatPrice(selectedVariantPrice.calculated_price.calculated_amount)77  }, [selectedVariantPrice])78
79  return (80    <div>81      {loading && <span>Loading...</span>}82      {product && (83        <>84          <h1>{product.title}</h1>85          {(product.options?.length || 0) > 0 && (86            <ul>87              {product.options!.map((option) => (88                <li key={option.id}>89                  {option.title}90                  {option.values?.map((optionValue) => (91                    <button 92                      key={optionValue.id}93                      onClick={() => {94                        setSelectedOptions((prev) => {95                          return {96                            ...prev,97                            [option.id!]: optionValue.value!,98                          }99                        })100                      }}101                    >102                      {optionValue.value}103                    </button>104                  ))}105                </li>106              ))}107            </ul>108          )}109          {selectedVariant && (110            <span>Selected Variant: {selectedVariant.id}</span>111          )}112          {price && (113            <span>114              {!selectedVariant && "From: "}115              {price}116            </span>117          )}118          {product.images?.map((image) => (119            <img src={image.url} key={image.id} />120          ))}121        </>122      )}123    </div>124  )125}

In the example above, you:

  • Use the useRegion hook defined in the previous Region React Context guide to retrieve the selected region's currency code. This is necessary to format the variant's price.
  • Pass the pricing query parameters to the request retrieving the product. This retrieves for every variant a new calculated_price field holding details about the variant's price.
  • Choose the variant to show its price:
    • If there's a selected variant, choose it.
    • If there isn't a selected variant, retrieve and choose the variant with the cheapest price.
  • Format the price based on the chosen variant in the previous step. The variant's calculated_price.calculated_amount field is used.
  • Display the formatted price to the customer. If there isn't a select variant, show a From label to indicate that the price shown is the cheapest.
Was this page helpful?
Ask Anything
Ask any questions about Medusa. Get help with your development.
You can also use the Medusa MCP server in Cursor, VSCode, etc...
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