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