Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Payment Failed Error Block for React

A full-screen page for a declined card payment: the order, the bank's answer, four reasons that each change the fix, and three ways to pay, with a Shine Button that follows the method.

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

Tell shoppers they weren't charged, and what to do next, with this payment failed page for React with Base UI. It's the screen Tuftmoor, a rug shop, shows when a card payment is declined: the page's two side rails run its full height and one band crosses the screen between two rules with a plus mark where each meets a rail. One inset Frame of three panels holds the order (three lines in whole cents, the total summed from them, and the bank's answer as an outline Badge, Card declined (05)), a Toggle Group of four reasons (not enough money, an expired card, the bank said no, details wrong) and three native radio cells for the method: Card, Bank transfer and Wallet. Each reason changes the fix line under it, and two bring a field with them: an expiry checked against a fixed month, and a card number that is spaced, matched to a brand by its first digits and run through the Luhn check, in this tab's memory only. The Shine Button is the only coloured control and its label follows the method. Pressing it checks the open field, waits a moment and says that nothing was charged; Start over puts everything back. It is the page after one failed payment, not the checkout step itself. For any shop that takes cards.

FAQ

What does the button do, and what stays in the page?

Nothing is paid and nothing leaves the page. The button checks the field that is open (the expiry or the card number), shows a spinner for under a second and then a polite status line says that nothing was charged and what a real page would hand over: the card details, the transfer or the wallet payment. Focus moves to that line because the busy button drops it. To wire it for real, start the payment from pay with your provider's hosted fields or payment element, and keep the order and the hold time on your server.

Is it safe to type a card number into this?

Not in your own app: use your payment provider's hosted fields, so the number never reaches your page or your servers. In this demo the field exists to show the checks. What you type is spaced into groups, its brand is read from the first digits, its length is counted and it is run through the Luhn check, all in the page's own state; nothing is stored, logged or sent, it is dropped as soon as the button has used it, and only the brand and the last four digits are kept ("Visa ending 4242").

What does each reason change?

The fix line and, for two of them, a field. Not enough money and The bank said no only say what to do (try again later, or call the number on the card). Expired card asks for the new expiry, which must be a real month that has not passed against a fixed "today". Details wrong asks for the card number again. All four fixes share one cell of the panel, so choosing a reason never changes the page's height, and a message under a field says what is wrong without moving anything.

Where do the amounts and the hold time come from?

The order lines are typed in whole cents in LINES, the total is summed from them and every amount is formatted with Intl.NumberFormat, so the text can't disagree with itself and nothing is rounded twice. "Held until 14:30 UTC" is typed clock text: in your app it comes from the order on your server, and a visitor's own clock plays no part.

How do the choices work with the keyboard?

The reasons are one single-choice toggle group: Tab reaches it and the arrow keys move between reasons, and one is always chosen. The methods are native radio buttons in a labelled group, so the arrow keys move between them too, and the chosen cell is a solid tint with a heavy edge and a filled dot, never colour alone.

What changes on a phone?

The reasons go two across and the three methods stack. The button is pinned to the foot of the screen so it stays in reach while you read, and its status line is read aloud there and shown on larger screens.

  • Pro

    Coupon Invalid Error

    Plans and checkout

    A panel for a promo code that no longer works: the failed code with why, the offers that do work for this box ranked by saving, and the box's total recomputed as you choose.

  • Pro

    Form Validation Error

    Files and data

    A panel for a request sent with problems: a table of what was found in two groups, must fix and check this, each row with what was typed, the rule and one fix control, and a Shine Button that warns once.

  • Pro

    Booking Unavailable Error

    Plans and checkout

    A full-screen page for a time that was just taken: the booked slot as a struck chip, the next free times grouped by day, a Shine Button that follows the choice, and a waitlist switch that opens an email field.

  • Pro

    Subscription Required Error

    Plans and checkout

    A full-screen 403 for a feature the plan does not include: the facts, what Pro adds, and an editable message that asks the workspace owners, with a Viewing as demo control that turns the ask into an upgrade with the price worked out.

  • Pro

    Sold Out Size Error

    Plans and checkout

    A full-screen page for a sold-out size: a drawn sweater, a row of five sizes with the sold-out ones struck, a notify field and Shine Button that follow the chosen size, and two similar knits in stock.

  • Pro

    A full-height page for a feature that is not on for your workspace yet: three conditions ruled from rail to rail, a rollout meter with the next wave, and a Switch that joins early access and flips the last condition.