asafefe.dev

Cart Summary

New

A checkout card with quantity steppers, removable lines, a promo field that shakes on a wrong code, rolling totals and a free shipping bar.

motionlucide-reactutilsbuttonbutton-groupcardemptyfieldinput-groupitemprogressseparatorspinner@soultel/rolling-number@soultel/use-reduced-motion-safe
Your bag
0123456789items
Market Tote

Canvas, Small

0123456789
$46.00
Stoneware Mug

Moss, 12 oz

0123456789
$22.00

Add $7.00 more for free shipping

x
Subtotal
$68.00
Shipping
$6.95
Total
$74.95

Try the code SAVE10

Installation

$ pnpm dlx shadcn@latest add @soultel/cart-summary

No namespace set up? npx shadcn@latest add https://asafefe.dev/r/cart-summary.json works too.

Manual installation
  1. 1. Install the dependencies.
    terminal1 lines
    npm install motion lucide-react
  2. 2. Copy the source from the Code tab into components/cart-summary.tsx.

Usage

example.tsx14 lines
import { CartSummary } from "@/components/cart-summary"

export function Checkout() {
  return (
    <CartSummary
      defaultItems={[
        { id: "tee", name: "Heavyweight Tee", variant: "Oat, M", price: 32, quantity: 2, color: "#c9a77c" },
        { id: "mug", name: "Stoneware Mug", variant: "Ember, 12 oz", price: 18, quantity: 1, color: "#e2412f" },
      ]}
      promoCodes={{ SAVE10: { percent: 10 }, WELCOME5: { amount: 5, label: "$5 off your first order" } }}
      onCheckout={(items, totals) => startCheckout(items, totals)}
    />
  )
}

Props

PropTypeDefaultDescription
items / defaultItemsCartItem[]-Controlled or initial lines: id, name, price, quantity, and optional variant, max, color, image.
onItemsChange(items: CartItem[]) => void-Called when a quantity changes or a line is removed.
promoCodesRecord<string, PromoCode>{}Valid codes, matched without case: { percent } or { amount }, with an optional label.
freeShippingThresholdnumber75Subtotal after discount that makes shipping free. 0 hides the bar.
shippingCostnumber6.95Flat shipping below the threshold.
currencystring"$"Symbol shown before prices.
onCheckout(items, totals) => void | Promise<void>-Called with the lines and subtotal, discount, shipping, total and promo. A promise shows a pending state.