# Price

> A React price component written the way shops print prices: a smaller currency, a struck old price with a discount chip, Negotiable, Free.

- Type: React component (Commerce)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add price`
- Docs: https://wingo-ui.com/components/price

## Interaction

A price is text: it reads in order ("$1,200, Negotiable", "$499, Was $649, 23% off") and nothing in it takes focus, a tap or a key. When the amount changes it fades to the new one, or rolls its digits like an odometer with animate="roll"; with announce a screen reader hears the new total once, never on mount. Under reduced motion the new value simply appears. On a narrow phone the amount never breaks; the old price, the chip and the captions wrap below it.

## Installation

```bash
npx wingo-ui@latest add price
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/price` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/ui/price.tsx`

npm dependencies: `npm i motion`

Wingo UI dependencies (installed automatically):

- [Animated Counter](https://wingo-ui.com/components/animated-counter) ([Markdown](https://wingo-ui.com/components/animated-counter.md))
- [Badge](https://wingo-ui.com/components/badge) ([Markdown](https://wingo-ui.com/components/badge.md))
- [useLocale](https://wingo-ui.com/components/use-locale) ([Markdown](https://wingo-ui.com/components/use-locale.md))
- [Commerce](https://wingo-ui.com/components/commerce) ([Markdown](https://wingo-ui.com/components/commerce.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
import { Price } from "@/components/ui/price"

export function ListingPrice() {
  return (
    <div className="flex flex-col gap-3">
      <Price price={320} priceType="negotiable" labels={{ negotiable: "Or best offer" }} />
      <Price
        price={499}
        compareAtPrice={649}
        size="lg"
        layout="stacked"
        labels={{ compare: "Was", discount: (percent) => `Save ${percent}%` }}
      />
      <Price price={489000} unit={{ quantity: 580, unit: "sq ft" }} />
      <Price price={1900} priceSuffix="/mo" caption="Utilities not included" />
    </div>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `price` | `number \| null` | `1200` | The amount in major units (dollars, not cents). null (or NaN) renders labels.onRequest ("Price on request"). |
| `currency?` | `string` | `"USD"` | ISO 4217 code, printed with its narrow symbol: "$", "€", "lei". An unknown code prints the number with the code ("1,200 XYZ"). |
| `locale?` | `string` | `""` | Intl locale for grouping, decimals and where the currency goes ("$1,200" in en-US, "1.200 €" in de-DE). Empty uses the UIProvider locale, then the page. |
| `fractionDigits?` | `"auto" \| "0" \| "2" \| number` | `"auto"` | auto prints whole amounts without decimals ("$1,200") and the currency's digits otherwise ("$1,284.90"); a number (or "0" / "2") forces that many. |
| `compareAtPrice?` | `number \| null` | `0` | The old price. Shown struck through, with the sale color and the discount chip, only when it is above price (and above 0); 0 or null means none. |
| `priceType?` | `"fixed" \| "negotiable" \| "free" \| "exchange" \| "on-request"` | `"fixed"` | negotiable adds labels.negotiable after the amount; free, exchange and on-request replace the amount with their label (free in the success color). |
| `priceSuffix?` | `string` | `""` | Muted text after the currency: "/mo", "/night", "/each". |
| `unit?` | `{ quantity: number; unit: string }` |  | Adds the price per unit to the caption: $489,000 for 580 sq ft prints "$843/sq ft". |
| `caption?` | `ReactNode` | `""` | One muted line under the price ("Tax included", "+ $9.99 shipping"), after the unit price when both are set. |
| `showDiscount?` | `boolean` | `true` | The "-25 %" chip next to the old price when on sale. Screen readers hear labels.discount instead of the chip. |
| `saleTone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"danger"` | The sale amount's color and the chip's tone. A markdown is a status, so it defaults to danger; the two prices still say it without color. |
| `size?` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | 14 / 17 / 22 / 32px amounts (xl grows to 40px from 768px): a cart line, a card, a detail page, a pricing hero. |
| `currencyStyle?` | `"small" \| "inline"` | `"small"` | small sets the currency at 0.72em of the amount, in the locale's order; inline prints it at the same size. |
| `layout?` | `"inline" \| "stacked"` | `"inline"` | inline keeps everything on one line and wraps between parts; stacked puts the old price, the chip and Negotiable on a second line (cards, plans). |
| `animate?` | `"none" \| "fade" \| "roll"` | `"fade"` | How a new amount appears: a quick keyed fade, digits rolling like an odometer (totals, plans), or nothing. Reduced motion always swaps instantly. |
| `announce?` | `boolean` | `false` | Reads a changed price out politely through a live region (cart and checkout totals). Never on mount. |
| `labels?` | `Partial<PriceLabels>` |  | Copy: negotiable "Negotiable", free "Free", exchange "Swap", onRequest "Price on request", compare "Was" (sr-only before the old price), discount (percent) => "25% off" (sr-only when the chip shows). Pass only the keys you translate. |
| `classNames?` | `Partial<Record<"current" \| "amount" \| "currency" \| "suffix" \| "label" \| "compare" \| "discount" \| "negotiable" \| "caption", string>>` |  | Extra classes for the inner parts. |
| `className?` | `string` |  | Extra classes for the root span, merged last. Other span props (id, aria-*, data-*) spread onto it. |

## Parts

### PRICE_SIZES (constant)

The type classes of each size (amount, compare, caption and the badge size), for bars and tables that print a price without the component but should match it.

### DEFAULT_PRICE_LABELS (constant)

The English copy: negotiable "Negotiable", free "Free", exchange "Swap", onRequest "Price on request", compare "Was" and discount "25% off".

## Examples

- **Sale in every size**: An old price struck through with its discount chip, inline and stacked.
- **Listing types**: Negotiable after the amount; free, swap and on request instead of it.
- **Real estate**: The price per unit of area as a caption, in dollars and in euros.
- **Rent and stays**: A muted suffix after the currency, with a brand sale tone.
- **A changing total**: Digits roll as the quantity changes and the new total is announced.
- **Locales**: Grouping, decimals and the currency's side follow the locale.
- **B2B caption**: A muted line under the amount for prices before tax.

## See also

- [Listing card](https://wingo-ui.com/components/listing-card) ([Markdown](https://wingo-ui.com/components/listing-card.md))
- [Price range](https://wingo-ui.com/components/price-range) ([Markdown](https://wingo-ui.com/components/price-range.md))
- [Cart drawer](https://wingo-ui.com/components/cart-drawer) ([Markdown](https://wingo-ui.com/components/cart-drawer.md))
- [Pricing table](https://wingo-ui.com/components/pricing-table) ([Markdown](https://wingo-ui.com/components/pricing-table.md))
- [Currency Input](https://wingo-ui.com/components/currency-input) ([Markdown](https://wingo-ui.com/components/currency-input.md))
- [Animated Counter](https://wingo-ui.com/components/animated-counter) ([Markdown](https://wingo-ui.com/components/animated-counter.md))

---

Canonical: https://wingo-ui.com/components/price
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
