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_tax
fromcalculated_amount_with_tax
to get the tax amount.is_calculated_price_tax_inclusive
: Whether thecalculated_amount
property includes taxes. If enabled, you can display thecalculated_amount
property 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
useRegion
hook 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
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, 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_price
field 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_tax
property.