Skip to content
All Taste components

Animated app UI

Payment success

A confirmation card where the circle and tick draw themselves and a small burst of colour settles around them.

drawn circle · drawn tick · confetti burst · receipt rows · two actions

Payment successful

₹12,480 paid to Kestrel Studio. A receipt is on its way to your inbox.

Reference
PAY-7F3K29
Method
Visa ·· 4417
Date
15 Oct, 10:42
import { CalendarDays, CreditCard, Receipt } from "lucide-react";
import { cn } from "@/lib/utils";

/* Add once to globals.css (draw, rise and pop come from the Taste preset):
@keyframes burst { from { opacity: 0; transform: translate(-50%, -50%) scale(.2); } }
*/

// Final resting place of each confetti piece around the tick (px), its colour and shape.
const confetti = [
  { x: -60, y: -14, r: 20, c: "var(--tst-primary)", bar: true }, { x: -46, y: -46, r: 0, c: "var(--tst-warning)" },
  { x: -12, y: -64, r: -30, c: "var(--tst-info)", bar: true }, { x: 24, y: -58, r: 0, c: "var(--tst-success)" },
  { x: 52, y: -36, r: 40, c: "var(--tst-danger)", bar: true }, { x: 64, y: 2, r: 0, c: "var(--tst-primary)" },
  { x: 52, y: 38, r: -25, c: "var(--tst-warning)", bar: true }, { x: 18, y: 60, r: 0, c: "var(--tst-info)" },
  { x: -22, y: 58, r: 15, c: "var(--tst-success)", bar: true }, { x: -54, y: 34, r: 0, c: "var(--tst-danger)" },
  { x: -70, y: 14, r: 0, c: "var(--tst-info)" }, { x: 40, y: -66, r: 0, c: "var(--tst-primary)" },
];
const receipt = [
  { label: "Reference", value: "PAY-7F3K29", icon: null },
  { label: "Method", value: "Visa ·· 4417", icon: CreditCard },
  { label: "Date", value: "15 Oct, 10:42", icon: CalendarDays },
];

export function PaymentSuccess() {
  return (
    <section aria-labelledby="ok-title" className="mx-auto grid max-w-[400px] justify-items-center gap-1.5 rounded-lg border border-border bg-bg px-[22px] pb-[22px] pt-8 text-center font-sans">
      <div aria-hidden className="relative mb-7 mt-2.5 size-[84px]">
        <span className="absolute inset-[7px] rounded-full bg-success-soft animate-pop [animation-delay:100ms] motion-reduce:animate-none" />
        {confetti.map((p, i) => (
          <span
            key={i}
            className={cn("absolute left-1/2 top-1/2 animate-[burst_.9s_cubic-bezier(.34,1.56,.64,1)_both] motion-reduce:animate-none", p.bar ? "h-[11px] w-1 rounded-sm" : "size-[7px] rounded-full")}
            style={{
              background: p.c,
              transform: "translate(-50%, -50%) translate(" + p.x + "px, " + p.y + "px) rotate(" + p.r + "deg)",
              animationDelay: 640 + i * 18 + "ms",
            }}
          />
        ))}
        <svg viewBox="0 0 84 84" className="absolute inset-0 size-full">
          <circle cx="42" cy="42" r="34" pathLength={1} transform="rotate(-90 42 42)" className="fill-none stroke-success [stroke-dasharray:1] [stroke-width:3] animate-[draw_.65s_cubic-bezier(.2,.7,.1,1)_.15s_both] motion-reduce:animate-none" />
          <path d="m29 43 9 9 18-19" pathLength={1} className="fill-none stroke-success [stroke-dasharray:1] [stroke-linecap:round] [stroke-linejoin:round] [stroke-width:4] animate-[draw_.38s_cubic-bezier(.2,.7,.1,1)_.62s_both] motion-reduce:animate-none" />
        </svg>
      </div>

      <h2 id="ok-title" className="text-[22px] font-medium tracking-tight text-fg animate-rise [animation-delay:700ms] motion-reduce:animate-none">Payment successful</h2>
      <p className="text-[13.5px] leading-relaxed text-fg-muted animate-rise [animation-delay:770ms] motion-reduce:animate-none">
        ₹12,480 paid to Kestrel Studio. A receipt is on its way to your inbox.
      </p>

      <dl className="mb-1 mt-3.5 w-full rounded bg-surface px-3.5 py-1 text-left animate-rise [animation-delay:860ms] motion-reduce:animate-none">
        {receipt.map((r) => (
          <div key={r.label} className="flex justify-between gap-3 border-b border-dashed border-border py-2.5 text-[13px] last:border-0">
            <dt className="text-fg-muted">{r.label}</dt>
            <dd className="flex items-center gap-1.5 font-medium tabular-nums text-fg">{r.icon && <r.icon className="size-3.5" aria-hidden />}{r.value}</dd>
          </div>
        ))}
      </dl>

      <div className="mt-2 flex w-full gap-2.5 animate-rise [animation-delay:940ms] motion-reduce:animate-none">
        <a href="/receipts/PAY-7F3K29" className="inline-flex h-9 flex-1 items-center justify-center gap-1.5 rounded border border-border-strong bg-bg text-sm font-medium text-fg transition hover:bg-surface active:scale-[.97]">
          <Receipt className="size-4" aria-hidden />View receipt
        </a>
        <a href="/" className="inline-flex h-9 flex-1 items-center justify-center rounded bg-primary text-sm font-medium text-primary-fg transition hover:bg-primary-hover active:scale-[.97]">Done</a>
      </div>
    </section>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.