Price

Tabular price with compare-at strike, sale color, savings chip, and per-unit or per-serving pricing.

ui
$npx shadcn@latest add @storekit/price
price

Live and interactive. Switch the brand in the frame header to see the same source under another token file.

Installation

$npx shadcn@latest add @storekit/price
$pnpm dlx shadcn@latest add @storekit/price
$yarn dlx shadcn@latest add @storekit/price
$bunx --bun shadcn@latest add @storekit/price

Source

components/storekit/ui/price.tsx
46 lines
"use client"

import { cn, money } from "@/components/storekit/lib/cn"

/* Price with optional compare-at and savings. Tabular numerals so prices in a
   grid line up. The amount is in integer cents. `per` adds unit economics in
   muted text, e.g. { amount: 112, unit: "serving" } renders "$1.12 / serving". */

export function Price({
  amount,
  compareAt,
  className,
  size = "md",
  showSavings = false,
  suffix,
  per,
}: {
  amount: number
  compareAt?: number
  className?: string
  size?: "sm" | "md" | "lg" | "xl"
  showSavings?: boolean
  suffix?: string
  /** Unit economics: amount in integer cents per one unit ("serving", "day", "each"). */
  per?: { amount: number; unit: string }
}) {
  const onSale = typeof compareAt === "number" && compareAt > amount
  const sizes = { sm: "text-sm", md: "text-base", lg: "text-xl", xl: "text-3xl" }[size]
  const pct = onSale ? Math.round((1 - amount / compareAt) * 100) : 0
  return (
    <span className={cn("inline-flex flex-wrap items-baseline gap-x-2 gap-y-0.5 tabular-nums", sizes, className)}>
      <span className={cn("font-semibold", onSale ? "text-sk-sale" : "text-sk-price")}>{money(amount)}</span>
      {onSale ? <s className="text-[0.8em] text-sk-muted decoration-sk-muted/60">{money(compareAt)}</s> : null}
      {onSale && showSavings ? (
        <span className="rounded-sk-chip bg-sk-savings/[0.12] px-1.5 py-0.5 text-[0.7em] font-semibold text-sk-savings">Save {pct}%</span>
      ) : null}
      {suffix ? <span className="text-[0.75em] text-sk-muted">{suffix}</span> : null}
      {per ? (
        <span className="text-[0.75em] font-normal text-sk-muted">
          {money(per.amount)} / {per.unit}
        </span>
      ) : null}
    </span>
  )
}

Usage

Import from "@/components/storekit/ui/price" and pass your product data. The demo above exercises the full prop surface with sample values.

Price, StoreKit