Example: Show Product Variant's Price with Taxes
In this guide, 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:
You pass the selected region's ID and the code of its first country as query parameters to the Get Product API route.
region.countries in a select input, and storing the selected country's code in the local storage.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. Learn more about how to set the selected variant for pricing in the Show Product Variant's Price guide.
Tax-Related Properties in Calculated Price#
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. This may be useful if you want to show the customer the price without taxes, and show the applied taxes separately. In that case, you can subtractcalculated_amount_without_taxfromcalculated_amount_with_taxto get the tax amount.is_calculated_price_tax_inclusive: Whether thecalculated_amountproperty includes taxes. If enabled, you can display thecalculated_amountproperty instead ofcalculated_amount_with_tax.
Learn more about the calculated_price object in the Retrieve Product Variant's Prices guide.
Full React Example#
For example, to display the price with taxes in a React-based storefront:
- This example uses the
useRegionhook defined in the Region React Context guide to retrieve the selected region's currency code. - Learn how to install and configure the JS SDK in the JS SDK documentation.
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 country_code: region.countries[0].iso_2,29 })30 .then(({ product: dataProduct }) => {31 setProduct(dataProduct)32 setLoading(false)33 })34 }, [loading])35 36 const selectedVariant = useMemo(() => {37 if (38 !product?.variants ||39 !product.options || 40 Object.keys(selectedOptions).length !== product.options?.length41 ) {42 return43 }44 45 return product.variants.find((variant) => variant.options?.every(46 (optionValue) => optionValue.value === selectedOptions[optionValue.option_id!]47 ))48 }, [selectedOptions, product])49 50 const formatPrice = (amount: number): string => {51 return new Intl.NumberFormat("en-US", {52 style: "currency",53 currency: region.currency_code,54 })55 .format(amount)56 }57 58 const selectedVariantPrice = useMemo(() => {59 if (selectedVariant) {60 return selectedVariant61 }62 63 return product?.variants?.sort((a: any, b: any) => {64 return (65 a.calculated_price.calculated_amount_with_tax -66 b.calculated_price.calculated_amount_with_tax67 )68 })[0]69 }, [selectedVariant, product])70 71 const price = useMemo(() => {72 if (!selectedVariantPrice) {73 return74 }75 76 // @ts-ignore77 return formatPrice(78 selectedVariantPrice.calculated_price?.calculated_amount_with_tax || 079 )80 }, [selectedVariantPrice])81 82 return (83 <div>84 {loading && <span>Loading...</span>}85 {product && (86 <>87 <h1>{product.title}</h1>88 {(product.options?.length || 0) > 0 && (89 <ul>90 {product.options!.map((option) => (91 <li key={option.id}>92 {option.title}93 {option.values?.map((optionValue) => (94 <button 95 key={optionValue.id}96 onClick={() => {97 setSelectedOptions((prev) => {98 return {99 ...prev,100 [option.id!]: optionValue.value!,101 }102 })103 }}104 >105 {optionValue.value}106 </button>107 ))}108 </li>109 ))}110 </ul>111 )}112 {selectedVariant && (113 <span>Selected Variant: {selectedVariant.id}</span>114 )}115 {price && (116 <span>117 {!selectedVariant && "From: "}118 {price}119 </span>120 )}121 {product.images?.map((image) => (122 <img src={image.url} key={image.id} />123 ))}124 </>125 )}126 </div>127 )128}
In this example, you:
- Use the
useRegionhook 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, including the selected region's ID and the code of its first country, to the request retrieving the product. This retrieves for every variant a new
calculated_pricefield holding details about the variant's price and taxes.- You can pass other pricing query parameters for more accurate pricing. Refer to the Retrieve Product Variant's Prices guide for more information.
- 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.
- Display the selected variant's price with taxes by formatting its price's
calculated_amount_with_taxproperty.