# Collect tax with Elements Learn how to calculate and display taxes using Checkout with elements mode. Stripe Tax automatically calculates the taxes on purchases when you use Checkout with elements mode (`ui_mode: 'elements'`). This integration gives you full control over the payment form layout while Stripe handles tax calculation. If you haven’t set up Checkout with elements mode, complete the [Checkout quickstart](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) first. ## Calculate and render tax amount ## Add tax registrations [Dashboard] [Server-side] Stripe Tax only collects tax in jurisdictions where you have an active registration. Add a registration for each country or state where you’re required to collect tax. To [create a registration](https://docs.stripe.com/api/tax/registrations/create.md): ```curl curl https://api.stripe.com/v1/tax/registrations \ -u "<>:" \ -d country={{COUNTRY_CODE}} \ -d "country_options[us][state]={{STATE}}" \ -d "country_options[us][type]=state_sales_tax" \ -d active_from=now ``` The `country_options` structure varies by country, for the full list of supported values, see [Tax Registrations API](https://docs.stripe.com/api/tax/registrations/create.md). Alternatively, add registrations in the Dashboard. Go to the **Tax** > [Registrations](https://dashboard.stripe.com/tax/registrations). You only need to add a registration once per jurisdiction. ## Configure your Checkout Session to collect tax To start collecting tax: 1. Pass [automatic_tax[enabled]=true](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-automatic_tax-enabled) when creating a Checkout Session. 1. Specify a [tax_code](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-price_data-product_data-tax_code) for each line item, or set a preset tax code in the [Dashboard](https://dashboard.stripe.com/settings/tax). 1. Specify a [tax_behavior](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-price_data-tax_behavior) for each line item, or set a default tax behavior in the [Dashboard](https://dashboard.stripe.com/settings/tax). This code enables automatic tax calculation using Stripe Tax, a tax code, and a tax behavior. Stripe Tax then uses the tax code and tax behavior to automatically calculate taxes. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][product_data][tax_code]=txcd_99999999" \ -d "line_items[0][price_data][unit_amount]=2000" \ -d "line_items[0][price_data][tax_behavior]=exclusive" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=elements \ -d return_url={{RETURN_URL}} \ -d "automatic_tax[enabled]=true" ``` #### Tax codes The tax codes associate products with tax rates. Choose the appropriate tax code for your product from the list of [tax codes](https://docs.stripe.com/tax/tax-codes.md). If a product doesn’t match with any of the tax codes, you can use one of the `General` codes. #### Tax behavior The [tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-behavior) determines how to present tax to the customer: - **Exclusive**: The product price doesn’t include tax, which is added as a separate amount. - **Inclusive**: The product price includes any tax amount. ## Optional: Collect tax address details through the Payment Element You can collect the minimum tax address details directly in the [Payment Element](https://docs.stripe.com/payments/payment-element.md). Collecting tax address details through the Payment Element is suitable for the following use cases: - You don’t require full address collection. - You only require address collection for tax collection purposes. This feature integrates input fields for the country and postal code into each payment method form within the Payment Element. It only collects the minimum required address fields for tax calculation based on [Stripe Tax requirements](https://docs.stripe.com/tax/customer-locations.md#supported-formats). There are certain [regional considerations](https://docs.stripe.com/tax/customer-locations.md#region-specific) where the tax rate using the minimum required address fields might differ from the tax rate at your customer’s full address. We recommend using the [Address Element](https://docs.stripe.com/elements/address-element.md) to collect your customer’s full address for tax calculation if these regional considerations apply to your business. When you create the Checkout Session, set [billing_address_collection=auto](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection) to automatically collect the billing address. Don’t include the [shipping_address_collection](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection) parameter. If you provide this parameter, tax address details are collected based on the shipping address instead of the billing address. With [automatic_tax[enabled]=true](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-automatic_tax-enabled) and `billing_address_collection=auto`, the Payment Element collects the minimum required tax address fields for each payment method. If you set [billing_address_collection=required](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection), you must collect a full billing address with the [Address Element](https://docs.stripe.com/elements/address-element.md) or your own address form. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][product_data][tax_code]=txcd_99999999" \ -d "line_items[0][price_data][unit_amount]=2000" \ -d "line_items[0][price_data][tax_behavior]=exclusive" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=elements \ -d return_url={{RETURN_URL}} \ -d "automatic_tax[enabled]=true" \ -d billing_address_collection=auto ``` ### Field-level address control When collecting tax address details through the Payment Element, tax calculation behaves as follows: - If you pass [fields.billingDetails.address=auto | if_required](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails-address), the Payment Element collects the minimum required address fields for tax calculation. - If you pass [fields.billingDetails.address=never](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails-address), you must collect tax address details through an alternative method because the billing input fields won’t show in the Payment Element. - If you pass [fields.billingDetails.address.country=never](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails-address-country), the customer’s detected country is used for tax calculation. - If you pass [fields.billingDetails.address.postalCode=never](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails-address-postalCode), the method returns an error because the postal code might be required for certain countries. - If you call [action.updateBillingAddress](https://docs.stripe.com/js/custom_checkout/update_billing_address), the method returns an error because the billing address could potentially conflict. ## Optional: Check the response You can view the calculated tax amount for each payment as follows: - In the Checkout Session resource, review the [total_details.amount_tax](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-total_details) property. - In the [Dashboard](https://dashboard.stripe.com/), review the tax outcome for each payment. ## Render the tax amount #### React Use the [useCheckoutElements](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout_elements) hook to display the tax amount in your payment form. ```jsx import React from 'react'; import {useCheckoutElements} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const checkoutState = useCheckoutElements(); if (checkoutState.type === 'loading') { return (
Loading...
); } else if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } const {checkout} = checkoutState; return (

Checkout Summary

        {JSON.stringify(checkout.lineItems, null, 2)}
      

Totals

        Subtotal: {checkout.total.subtotal.amount}
        {/* Make sure you use the appropriate tax amount type (taxInclusive and/or taxExclusive) for your integration */}
        Tax: {checkout.total.taxExclusive.amount}
        Total: {checkout.total.total.amount}
      
) }; ``` #### HTML + JS Use the [Session object](https://docs.stripe.com/js/custom_checkout/session_object) to display the tax amount in your payment form. ```html

Totals

``` ```js const checkout = stripe.initCheckoutElementsSdk({clientSecret}) const subtotal = document.getElementById('subtotal'); const tax = document.getElementById('tax'); const total = document.getElementById('total'); checkout.on('change', (session) => { subtotal.textContent = `Subtotal: ${session.total.subtotal.amount}`; // Make sure you use the appropriate tax amount type (taxInclusive and/or taxExclusive) for your integration tax.textContent = `Tax: ${session.total.taxExclusive.amount}`; total.textContent = `Total: ${session.total.total.amount}`; }) ``` ## Collect customer tax IDs [Set up tax ID collection](https://docs.stripe.com/tax/checkout/tax-ids.md) to collect VAT and other business tax IDs during checkout. After enabling collection on your Checkout Session, render the Tax ID Element in your payment form. ## Render the Tax ID Element [Client-side] [Public preview] Use Stripe’s [Tax ID Element](https://docs.stripe.com/js/custom_checkout/create_tax_id_element) to collect tax IDs. #### React ```jsx import {useMemo} from 'react'; import {loadStripe} from '@stripe/stripe-js'; import {CheckoutElementsProvider, TaxIdElement} from '@stripe/react-stripe-js/checkout'; const stripePromise = loadStripe('<>', { betas: [ 'custom_checkout_tax_id_1', ], }); const App = () => { const fetchClientSecret = useMemo(() => { return fetch('/create-checkout-session', {method: 'POST'}) .then((res) => res.json()) .then((data) => data.clientSecret) }, []); return ( ); }; ``` #### HTML + JS ```html
``` ```javascript const stripe = window.Stripe('<>', { betas: [ "custom_checkout_tax_id_1", ], }); const clientSecret = fetch("/create-checkout-session", { method: "POST", headers: { "Content-Type": "application/json", }, }) .then((res) => res.json()) .then((res) => { return res.clientSecret; }); const checkout = stripe.initCheckoutElementsSdk({ clientSecret, }); const taxIdElement = checkout.createTaxIdElement(); taxIdElement.mount("#tax-id-element"); ``` ### Real-time tax ID validation (Preview) In addition to the asynchronous validation described above, you can enable synchronous, real-time tax ID verification directly in the Tax ID Element. When you enable it, Stripe verifies tax IDs against government databases as your customer types and displays the result inline before they submit the payment. Stripe currently supports real-time verification for [Australian Business Numbers (ABNs)](https://docs.stripe.com/tax/invoicing/tax-ids.md#australian-business-numbers-abn), [European Value Added Tax (EU VAT)](https://docs.stripe.com/tax/invoicing/tax-ids.md#european-value-added-tax-eu-vat-numbers), and [United Kingdom Value Added Tax (GB VAT)](https://docs.stripe.com/tax/invoicing/tax-ids.md#united-kingdom-value-added-tax-gb-vat-numbers) numbers. If a government database is unavailable, Stripe falls back to synchronous format validation and performs full verification asynchronously. This feature is in [public preview](https://docs.stripe.com/release-phases.md) and requires the `custom_checkout_tax_id_verification_1` beta. ```javascript const taxIdElement = checkout.createTaxIdElement({ ... verification: { taxId: { mode: 'if_supported', }, }, }); ``` When you enable verification, the `change` event includes the `verification.taxId.status` field. Its value can be `pending`, `verified`, `unverified`, or `unavailable`. The element’s `complete` status reflects the verification result. See [Create a Tax ID Element](https://docs.stripe.com/js/custom_checkout/create_tax_id_element#custom_checkout_create_tax_id_element-options-verification) and [Tax ID Element on Change](https://docs.stripe.com/js/custom_checkout/element_events/on_change?type=taxIdElement#custom_checkout_element_on_change-handler-verification) for details.