- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
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:
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.
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:
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:
calculated_amount_without_tax
: The calculated amount without taxes.is_calculated_price_tax_inclusive
: Whether thecalculated_amount
property includes taxes. If enabled, you can display it instead ofcalculated_amount_with_tax
.
Full React Example#
For example, in a React-based storefront:
region_id
query parameter for pricing. Learn how to store and retrieve the customer's region in the Regions guides .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.