KQ-1772 · FAILED/CHARGE

Failed Charge

An in-app banner for a payment that didn't go through, fixable in place: Retry tries the charge again and Update card opens a short form of saved methods or a new card that saves and retries in one go. While a retry is pending a tinted sweep fills across the banner on a long decelerating tween; when the charge lands it completes on springs.glide, the band turns from muted red to green, the check draws on springs.flick and the banner folds itself away on glide, while a refusal drains the sweep on the exit ease and simply states the reason. The message is a polite live region, the form is a radiogroup of methods (arrows) with labelled inputs, Enter submits and Escape closes it back to Update card.

KQ-1772 · FAILED/CHARGE
FernworksBilling

Your October payment of $284.00 didn't go through. The card was declined. INV-2026-10 · Card ending 4417

declined · 1 attempt

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/failed-charge

Props

invoice
FailedChargeInvoice
default INV-2026-10, $284.00, October
The invoice that failed: { id, number, amount, label }.
method
FailedChargeMethod
default card ending 4417
The method the charge was tried on: { id, label, kind }; the label reads mid-sentence.
methods
FailedChargeMethod[]
default a bank account ending 0921
Other saved methods to choose from in the update.
graceDays
number
default 7
Days the account stays active after the first failure.
failedAt
number
default Oct 15 2026
When the charge first failed, in ms.
now
number
default Oct 17 2026, 14:00 UTC
The moment grace is counted at, in ms.
reason
string
default "The card was declined."
Why the first attempt failed.
attempts / defaultAttempts
number
default — / 1
Failed attempts so far, controlled or initial; two or more shows the grace days.
onRetry
(methodId) => void | Promise
default —
Retry was pressed (or a new method was saved); resolve when paid, reject with the reason.
onUpdateMethod
(choice) => void | Promise
default —
The update form was submitted with a saved method or a new card's fields; resolve with the method to retry on.
open / defaultOpen
boolean
default — / true
Whether the banner is showing, controlled or initial.
onDismiss
(why: "user" | "paid") => void
default —
The banner folded away: dismissed by the reader, or paid.
expanded / defaultExpanded
boolean
default — / false
Whether the update form is open, controlled or initial.
onExpandedChange
(open) => void
default —
Fires from Update card, Cancel or Escape with the new state.
foldDelay
number
default 1600
How long Payment received stays before the banner folds, in ms.
bandStyle
"edge" | "wash" | "outline"
default "edge"
Where the colour sits: a leading band, the whole banner, or the border.
cornerRadius
number
default 10
Corner radius in px.
tone
"soft" | "strong" | "mono"
default "soft"
How loud the colour is.
account
string
default "Fernworks"
The product that stays active through the grace days.
formatMoney
(amount) => string
default Intl USD
How money is written.
className
string
default —
Classes for the region that holds the banner.