Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Payment Failure Recovery Billing Block for React Aria

A declined renewal diagnosed with three checks run against the account (card expiry, billing postal code, daily limit), a postal code fix on the failing one, and a Retry payment that unlocks once every check passes.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Find out why a payment failed before asking for a new card, with this payment failure recovery section for React with React Aria. It shows the account of Lanternroot, a meal-planning app, whose $49.00 renewal was declined on Oct 12. A hairline frame with a plus mark on each corner holds three checks worked out from the account's own data, each a word and a glyph with the fact it rests on: the Visa's expiry, the account's postal code against the one on the card statement, and the amount against the card's daily limit. The failing check carries its fix inline, a postal code Input that stays in place when the check passes. Beside the checks, the failed charge (amount, method, status) sits over the one Shine Button, Retry payment, which stays quiet until every check passes, then waits a moment and settles the charge: the heading becomes "Paid. Your subscription stays active". On a phone the checks come first and the charge and the button follow. It's built from Badge, Field, Input, Shine Button and Guides, with a CSS entrance only. For dunning pages, failed-payment banners and any subscription app.

FAQ

Where do the three checks come from?

They are derived, not typed. checksOf takes the postal code as typed and compares the account's data in CHARGE: the card's expiry month against AS_OF, the postal code against the one on the card statement, and the amount against the card's daily limit. Each returns a name, a sentence and whether it passes, and the heading's count, the words Passes and Fails and the Retry button all read the same result. In your app these facts come from your payment provider's decline code and the customer's records; a decline reason from a bank is often vaguer, so word each check as a likely cause.

How does the postal code fix work?

The field takes five digits and drops anything else. When it matches the statement's code the check passes, its sentence changes and Retry payment unlocks. The field never disappears, so the rows keep their height. Pressing Retry while a check fails says which one to fix, shows the field's own message if it is not five digits, and moves focus to the field.

What does Retry payment do here, and how do I wire it up?

It waits 600 milliseconds, marks the charge as paid, moves focus to the new heading and says "Paid in this demo. Nothing was charged." in a polite status message. Nothing is sent. In your app update the billing address through your provider, retry the invoice on your server, and show the result; a decline can happen again for a new reason, so keep the checks and rerun them from the response.

Is it accessible?

Every check says Passes or Fails in words with a glyph, never only a tone, and the sentence under it says why. The postal field is labelled, described by its message and marked invalid when it needs attention. The button keeps its size while it waits and a polite status message speaks the result.

How does it look on a phone?

The three checks stack in the order they are read, each row with its glyph, its sentence and its word, then the failed charge and Retry payment under them, as one column. From the medium breakpoint the charge sits in a side cell beside the checks.