Components

Morphing Checkout Flow

A three-step card payment where the container appears to animate height: auto - the active step is measured and the box eases to its px while steps slide past each other. The field re-masks on every keystroke (4-4-4-4, or 4-6-5 the moment it detects an Amex) yet the caret never jumps: it is put back by counting the digits before it, the only characters you actually own. Full numbers are checked against Luhn, brand detection cross-fades the logo on a live card that flips in 3D when you focus the CVC (an Amex never flips - its code lives on the front), and paying FLIPs the button's width from measured px into a spinner circle, then a drawn check. Tick Decline the payment and the same circle lands on a red ✕ instead, shakes once, and eases back for another try.

Step 1 of 3: card details

Step: card · Brand: unknown · Number: empty · Side: front

Install

npx moumenlab add morphing-checkout

For AI

Open .md

Usage

"use client";

import MorphingCheckout from "./morphing-checkout";

export default function MorphingCheckoutExample() {
  return (
    <div className="flex flex-col items-center gap-10">
      {/* Wire onPay to your real charge — return "decline" to fail, anything
          else to succeed. Async is fine (the button spins while it resolves). */}
      <MorphingCheckout
        price="$149.00"
        onPay={async ({ number }) => {
          const res = await fetch("/api/charge", { method: "POST", body: JSON.stringify({ number }) });
          return res.ok ? "success" : "decline";
        }}
      />

      {/* indicator="bar" swaps the segmented tabs for a loading bar that is also
          the tabs; outcome forces the demo verdict without an onPay. */}
      <MorphingCheckout indicator="bar" outcome="decline" />
    </div>
  );
}