Example: Show Product Variant's Price with Taxes

In this document, you'll learn how to show a product variant's price with taxes, with a full React example.

Retrieve Variant's Price with Tax#

To retrieve a product variant's price with taxes, you must pass the region_id and country_code query parameters:

Code
1const queryParams = new URLSearchParams({2  fields: `*variants.calculated_price`,3  region_id: region.id,4  country_code: region.countries[0].iso_2,5})6
7fetch(`http://localhost:9000/store/products/${id}?${queryParams.toString()}`, {8  credentials: "include",9  headers: {10    "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",11  },12})13.then((res) => res.json())14.then(({ product }) => {15  // TODO use product16  console.log(product)17})

You pass the selected region's ID and the code of its first country as query parameters to the Get Product API route.

TipYou can instead allow the customer to choose their country.

Display Variant's Price with Taxes#

After passing the region_id and country_code as query parameters when retrieving the product, each variant's price object will have a calculated_amount_with_tax property to indicate the price taxes applied:

Code
const price = formatPrice(selectedVariantPrice.calculated_price.calculated_amount_with_tax)

Where selectedVariantPrice is either the variant the customer selected or the cheapest variant.

TipLearn more about the formatPrice function in this guide

Tax Price Properties#

Aside from the calculated_amount_with_tax property, a variant's calculated_price object has the following properties related to taxes:

  1. calculated_amount_without_tax: The calculated amount without taxes.
  2. is_calculated_price_tax_inclusive: Whether the calculated_amount property includes taxes. If enabled, you can display it instead of calculated_amount_with_tax.

Full React Example#

For example, in a React-based storefront:

NoteThe example passes the region_id query parameter for pricing. Learn how to store and retrieve the customer's region in the Regions guides.
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"6
7type Params = {8  params: {9    id: string10  }11}12
13export default function Product({ params: { id } }: Params) {14  const [loading, setLoading] = useState(true)15  const [product, setProduct] = useState<16    HttpTypes.StoreProduct | undefined17  >()18  const [selectedOptions, setSelectedOptions] = useState<Record<string, string>>({})19  const region = useRegion()20
21  useEffect(() => {22    if (!loading) {23      return 24    }25
26    const queryParams = new URLSearchParams({27      fields: `*variants.calculated_price`,28      region_id: region.id,29      country_code: region.countries[0].iso_2,30    })31
32    fetch(`http://localhost:9000/store/products/${id}?${queryParams.toString()}`, {33      credentials: "include",34      headers: {35        "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",36      },37    })38    .then((res) => res.json())39    .then(({ product: dataProduct }) => {40      setProduct(dataProduct)41      setLoading(false)42    })43  }, [loading])44
45  const selectedVariant = useMemo(() => {46    if (47      !product?.variants ||48      !product.options || 49      Object.keys(selectedOptions).length !== product.options?.length50    ) {51      return52    }53
54    return product.variants.find((variant) => variant.options?.every(55      (optionValue) => optionValue.value === selectedOptions[optionValue.option_id!]56    ))57  }, [selectedOptions, product])58
59  const formatPrice = (amount: number): string => {60    return new Intl.NumberFormat("en-US", {61      style: "currency",62      currency: region.currency_code,63    })64    .format(amount)65  }66
67  const selectedVariantPrice = useMemo(() => {68    if (selectedVariant) {69      return selectedVariant70    }71
72    return product?.variants?.sort((a: any, b: any) => {73      return (74        a.calculated_price.calculated_amount_with_tax -75        b.calculated_price.calculated_amount_with_tax76      )77    })[0]78  }, [selectedVariant, product])79
80  const price = useMemo(() => {81    if (!selectedVariantPrice) {82      return83    }84
85    // @ts-ignore86    return formatPrice(87      selectedVariantPrice.calculated_price.calculated_amount_with_tax88    )89  }, [selectedVariantPrice])90
91  return (92    <div>93      {loading && <span>Loading...</span>}94      {product && (95        <>96          <h1>{product.title}</h1>97          {(product.options?.length || 0) > 0 && (98            <ul>99              {product.options!.map((option) => (100                <li key={option.id}>101                  {option.title}102                  {option.values?.map((optionValue) => (103                    <button 104                      key={optionValue.id}105                      onClick={() => {106                        setSelectedOptions((prev) => {107                          return {108                            ...prev,109                            [option.id!]: optionValue.value!,110                          }111                        })112                      }}113                    >114                      {optionValue.value}115                    </button>116                  ))}117                </li>118              ))}119            </ul>120          )}121          {selectedVariant && (122            <span>Selected Variant: {selectedVariant.id}</span>123          )}124          {price && (125            <span>126              {!selectedVariant && "From: "}127              {price}128            </span>129          )}130          {product.images?.map((image) => (131            <img src={image.url} key={image.id} />132          ))}133        </>134      )}135    </div>136  )137}

In this example, you:

  • Pass the selected region's ID and the code of its first country as query parameters to the Get Product API route.
    • You can instead allow the customer to choose their country.
  • Display the selected variant's price by formatting its price's calculated_amount_with_tax property.
Was this page helpful?
Edit this page