# Tax basis

Whether a price includes tax, as a badge the price sits inside: filled when the tax is in the figure, hollow when it is left out. Hover explains the tax, its rate and the price on the other basis. Use it on a figure, alone in a column header, or show a price on both bases at once so an ex-tax figure can be checked against the shelf.

Docs: https://ui.twelfth.ai/tax-basis · Category: Pricing · Updated: 2026-11-02

## Install

```bash
npx shadcn@latest add https://ui.twelfth.ai/r/tax-basis.json
```

```tsx
import { PriceFigure, TaxBasisMark } from "@/components/ui/tax-basis"
```

## Example

```tsx
<PriceFigure
  value={136.35}
  basis="exclusive"
  taxBasis="both"
  taxLabel="GST"
  taxRatePct={10}
/>
```

## Inc and ex, any tax label

Short single-word labels print as they are; longer ones print as "tax" and keep the full label in the title and spoken text.

```tsx
<TaxBasisMark basis="inclusive" taxLabel="VAT" />  // INC VAT, filled
<TaxBasisMark basis="exclusive" taxLabel="GST" />  // EX GST, hollow
<TaxBasisMark basis="exclusive" taxLabel="Sales tax" /> // EX TAX
```

## show, both, hide

both needs a rate. Without one it shows the one figure; without a basis it shows no mark at all.

```tsx
<PriceFigure value={136.35} basis="exclusive" />                             // $136.35 EX GST
<PriceFigure value={136.35} basis="exclusive" taxBasis="both" taxRatePct={10} /> // … $149.99 INC GST
<PriceFigure value={136.35} basis="exclusive" taxBasis="hide" />             // $136.35
<PriceFigure value={136.35} basis="exclusive" taxBasis="both" />             // no rate: one figure
<PriceFigure value={136.35} basis={null} taxBasis="both" taxRatePct={10} />  // no basis: no mark
```

## Named once, in a header

A column on one basis names it in the header and hides it in the cells.

```tsx
<th>Our price <TaxBasisMark basis="exclusive" taxLabel="GST" /></th>
<td><PriceFigure value={21.35} basis="exclusive" taxBasis="hide" /></td>
```

## Both, stacked, in a list

```tsx
<PriceFigure value={22.72} basis="inclusive" taxBasis="both" taxLabel="VAT" taxRatePct={20} locale="en-GB" currency="GBP" stacked />
```

## PriceFigure props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` (required) | `number \| null` |  | The price, on basis. null prints —. |
| `basis` (required) | `"inclusive" \| "exclusive" \| null` |  | The basis value is on. null when the source did not say: no mark, nothing converted. |
| `taxBasis` | `"show" \| "hide" \| "both"` | `"show"` | The figure with its mark, the figure alone, or the price on both bases. |
| `taxLabel` | `string` | `"GST"` | GST, VAT, GST/HST, Sales tax… |
| `taxRatePct` | `number \| null` | `null` | The rate behind both, in percent. Outside 0–30 counts as unknown. |
| `short` | `boolean` | `false` | Badges print inc / ex without the label. |
| `explain` | `"focus" \| "hover" \| false` | `"focus"` | How the badge explains the tax. |
| `note` | `ReactNode` |  | A further line for the hover, e.g. how it was converted. |
| `stacked` | `boolean` | `false` | With both, the second figure goes underneath. |
| `format` | `(value: number) => string` |  | Formats each figure; defaults to formatMoney. |
| `locale / currency` | `string` | `"en-AU" / "AUD"` | For the default format. |

## TaxBasisMark props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `basis` (required) | `"inclusive" \| "exclusive"` |  | Filled for inclusive, hollow for exclusive. |
| `taxLabel` | `string` | `"GST"` | The tax's name. |
| `short` | `boolean` | `false` | inc / ex only, where width is tight. |
| `children` | `ReactNode` |  | The figure the badge holds; omit for the basis alone. |
| `taxRatePct / other / note` | `number \| string \| ReactNode` |  | Rate, other-basis price and a further line for the hover. |
| `explain` | `"focus" \| "hover" \| false` | `"focus"` | Tooltip on hover and focus, hover only (inside a link), or none. |

## otherBasisPrice / taxBasisWords props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `otherBasisPrice(value, basis, taxRatePct)` | `number \| null` |  | The price on the other basis; null without a basis or a plausible rate. |
| `taxBasisWords(basis, taxLabel)` | `string` |  | "including GST" / "excluding GST". |

## Notes

- Screen readers hear "including GST" / "excluding GST". Hover or focus explains the tax in full (GST: Goods and Services Tax), with the rate and the other-basis price when known. Use explain="hover" inside a link or button, explain={false} inside a tooltip.
- The badge takes its colours from the text around it, so it reads on a card, in a header and in an inverted tooltip without a variant.
- Never guesses: no basis means no badge, and no rate means no second figure and no rate in the hover.

---

twelfth UI: Open-source (MIT) shadcn components for category managers and retail buying teams, by twelfth (https://twelfth.ai). React and TypeScript on shadcn's Base UI styles and Tailwind CSS v4. Components take plain props and fetch no data. Every block: https://ui.twelfth.ai/llms.txt
