Back to elements
ElementMiscFree

Payment Button React component

A pay button that shows every step of a payment: the amount, a spinner while it processes, a drawn tick when it's paid, a shake and a clear message when a card is declined, and an optional press-and-hold mode that fills up before it charges.

When to use the Payment Button component

Use Payment Button as the final action of a checkout, a subscription upgrade or a donation form, where people need to see that the payment is happening and whether it worked.

Use hold mode for large or irreversible charges so a stray tap can't pay by accident.

Installation

Add the Payment Button component to your project with the shadcn CLI. It lands in components/payment-button.tsx as plain React + Tailwind CSS source you own and can edit.

Install
Copied!
npx shadcn@latest add https://reactframe.com/r/payment-button.json

Or copy the source by hand and install its dependencies:

Install
Copied!
npm install motion clsx tailwind-merge

Props

<PaymentButton /> accepts 11 props, all optional.

  • amount
    number
    Default: 49
  • currency
    string
    Default: "USD"
  • locale
    string
    Default: "en-US"
  • onPay

    Resolve to finish successfully; reject (or resolve false) to show the error state.

    () => Promise<boolean | void>
    Default: () => new Promise((r) => setTimeout(() => r(true), 1400))
  • mode

    click: pay on click. hold: press and hold for holdMs to pay (stops accidental charges).

    "click" | "hold"
    Default: "click"
  • holdMs
    number
    Default: 900
  • note

    Text under the button. Set to "" to hide.

    string
    Default: "Payments are encrypted and processed securely."
  • errorMessage
    string
    Default: "Card declined"
  • resetAfter

    Go back to idle this many ms after success or error (0 = stay).

    number
    Default: 2400
  • theme
    "dark" | "light"
    Default: "dark"
  • className
    string

FAQ

How do I connect it to my payment provider?
Pass an async onPay that calls your backend (Stripe, Paddle, Lemon Squeezy...). Resolve to show Paid, reject or return false to show the error.
What happens after success or an error?
It returns to idle after resetAfter milliseconds (2.4s by default). Set resetAfter={0} to keep the result, for example before redirecting to a receipt.
Is the hold mode accessible?
Yes. Holding Space or Enter works like holding the pointer, and the state changes are announced.

More Misc components

Speed Dial
Free
Scroll Progress Bar
Free
Animate on Scroll
Free
Social Links
Free
Focus Trap
Free
Share Buttons
Free