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:

TipFind the implementation of the formatPrice function in this guide.
Code
const price = formatPrice(selectedVariantPrice.calculated_price.calculated_amount_with_tax)

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


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

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
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