Unit Price

Puts every pack on a common unit price and marks the real cheapest, catching bulk packs and multi-buys that cost more per unit.

StopsBigger pack costs more per kg

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/unit-price.json

The files land in your project. They're yours to edit.

Usage

unit-price-usage.tsx
import { UnitPrice, type PriceOption } from "@/components/ui/unit-price"

<UnitPrice options={teas} value={picked} onValueChange={setPicked} />

What it catches

  • Bigger packs that cost more per unit
  • Multi-buy offers that cost more than buying singles
  • Shrinkflation: a smaller pack at the same price
  • The true cheapest per dimension (weight, volume, count)

Props

UnitPrice props
PropTypeDefault
options* (required)

Packs to compare, with price, size and unit.

PriceOption[]—
value

Controlled id of the chosen option.

string—
defaultValue

Initial choice when uncontrolled.

string—
onValueChange

Called with the chosen option id.

(id: string) => void—
basis

Override the quantity each kind is priced per (e.g. per kg).

Record<Dimension, { quantity: number; label: string }>DEFAULT_BASIS
currency

ISO 4217 currency code.

string"INR"
locale

Locale for money formatting.

string"en-IN"
label

Visible label of the options.

string"Compare by unit price"
cheapestLabel

Templates. `{name}`, `{amount}`, `{size}`, `{pct}`, `{offer}` are filled in.

string"Cheapest"
dealWorseText

Warning when a multi-buy costs more per unit.

string"{offer} costs {amount} more than buying singles."
bulkTrapText

Warning when a bigger pack costs more per unit.

string"Bigger isn't cheaper: {pct} more per {size} than {name}."
shrankText

Warning when a pack shrank at the same price.

string"Pack shrank from {size}: {pct} more per unit at the same…
pickedText

Readback of the picked option against the cheapest.

string"The same amount of {name} costs {amount} less."
switchLabel

Label of the switch-to-cheapest fix.

string"Switch to {name}"

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Options are a roving-tabindex radiogroup with arrow keys
  • Cheapest and warnings marked with icons and text
  • Findings in a polite live region

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Compares only the options and sizes you pass
  • Ignores quality, expiry and delivery costs

What it stops

Bigger pack costs more per kg

Also known as

unit price · price per 100g · grocery · blinkit · zepto · bigbasket · pack size · shrinkflation

Field type

Dependencies

Pairs well with