Skip to content
Sign in
Generative UIOrder summaryMenu

Order summary

The last step of agentic checkout: every line, charge and address in tabular figures, then a purchase that cannot happen by accident. Hold to pay, or press once to arm and once to confirm, with processing, placed and failed states.

Line items, free shipping, tax and the total in tabular figures. Hold the button until the bar fills to place the order.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/order-summary.json

Usage

tsx
import { OrderSummary } from "@/components/ui/chatcn/order-summary"

<OrderSummary
  merchant="Fieldhouse Running"
  items={cart.items}
  shipping={0}
  tax={cart.tax}
  currency="EUR"
  payment={{ brand: "Visa", last4: "4242" }}
  shippingAddress={{ name: "Rosa Delgado", lines: ["Rua da Rosa 112", "1200-389 Lisboa"] }}
  onConfirm={async () => ({ orderNumber: (await checkout.complete(cart.id)).number })}
/>

subtotal and total are worked out from the items when you leave them out. Resolve onConfirm with the order number for the receipt; throw an Error and its message becomes the failed state's instructions. Without a message, the card says nothing was charged and to try again or use another card.

A deliberate confirm

  • hold (default): press and hold for holdMs (1200). A filled layer wipes across the label, linear, so the progress is honest. Letting go early snaps back. Space and Enter can be held too.
  • step: Place order arms a Confirm and pay button that names the amount. A double click cannot confirm, and the step disarms after 8 s.
  • While streaming the order is still being assembled, and nothing can be paid.

Examples

Confirm step, compact

Items fold behind a count. Place order arms a second Confirm and pay button, and the bank declines.

States

Loading, still assembling, processing, placed with an order number, failed and empty.

Props

PropTypeNotes
items{ id, title, quantity, unitPrice, detail?, image? }[]Empty shows Your cart is empty
subtotal, totalnumberComputed when left out
shipping, shippingLabelnumber, string0 reads Free
tax, discountnumber, { label, amount }
currency, localestring
payment{ brand, last4, expiry? }Brand as text
shippingAddress{ name, lines }
onChangePayment, onChangeAddress() => voidShow Change links
confirmMode, holdMs"hold" | "step", numberDefault hold, 1200 ms
onConfirm() => Promise<{ orderNumber? }>Reject to fail
onCancel() => voidShows Cancel order
status, orderNumber, errorOrderStatusreview, processing, success, failed
receiptNoteReactNodeAfter success
layout"full" | "compact"compact folds the items behind a count
loading, streamingboolean
labelsPartial<OrderSummaryLabels>Every string the summary shows or announces, for translation. Totals, counts and names arrive as function arguments

Keyboard

KeyAction
Space or Enter, heldHold to pay. Releasing early cancels
EnterPlace order, then Confirm and pay (step mode)
TabChange links, the confirm button, Cancel order

Accessibility

  • The hold button says how long to hold. Processing and the armed step are announced through a polite status region; a failure is an alert.
  • Totals are a description list in tabular figures, so columns of money line up.
  • Placed is green with a check, failed is red with an alert icon, and both say it in words.

Motion

  • The hold fill animates clip-path, linear over holdMs, and returns in 200 ms. It stays under reduced motion because it is the progress itself.
  • The status icon swaps in with the 150 ms blur crossfade. Items fold by height in 200 ms in the compact layout.