shadcn.io is not affiliated with official shadcn/ui
Add Card Dialog Block for React
A transit wallet's payment methods page with its add-card dialog shown open: a card drawn in greys that fills in as you type, a number that groups itself and names its network, checks on the number, expiry and code, and an Add card button that keeps only the last four digits.
Installation
Overview
Let people pay with a new card, with this add-card dialog for React with Base UI. It opens from the Payment methods page of Wayfold, a city transit wallet: the page's header holds an outline Add card Button, and the page itself, a balance and the cards already saved, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog is a split. At the start a card drawn in greys fills in as you type: the number grouped by four (4, 6 and 5 for Amex) with dots for the digits to come, the name and the expiry. At the end are four Fields with Inputs: the number, which names its network in text as soon as the first digits say so, the name, the expiry and the security code, and a Switch for fast top-up. Add card, the only Shine Button, checks everything together: the card checksum, an expiry that hasn't passed and the code's length each have their own message, under their own field, and focus goes to the first one. A good card adds a row to the wallet that says only "ending 4242". For preview the dialog is drawn open in place when the page loads; the Add card button opens the real Dialog, with the same fields and the same state. For wallets, subscriptions, checkouts and any app that takes a card.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Add card button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same CardFields component and share the block's state, so a number typed in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
Is it safe to take a card number in this dialog?
Not in your app. Here the number is formatted and checked in memory and thrown away: after Add card only the last four digits, the network and the expiry are kept, and nothing is sent anywhere. A real checkout should never let a card number touch your own page or server. Take it with your payment provider's hosted fields, which draw the number, expiry and code in frames the provider controls, keeping card data off your page and out of your PCI scope, and show the card they return in the live card and the wallet row. Everything around the fields, the layout, the labels, the messages and the switch, stays as it is.
What does it check, and when?
When you press Add card, or Enter in any field. The number must have the right length for its network (16 digits, 15 for Amex) and pass the card checksum, and a card already in the wallet is refused; the name can't be empty; the expiry must read MM/YY and not be a month before the one the block treats as now (AS_OF); the code must have 3 digits, 4 for Amex. Each problem has its own sentence in the slot under its field, and focus moves to the first field with one. Once a message shows, it follows your typing and clears as soon as that field is right. The card networks are read from the first digits (Visa 4, Mastercard 51 to 55 and 2221 to 2720, Amex 34 and 37) and written in text with a two-letter tile, never a logo.
How does the number format itself?
As you type, anything that isn't a digit is dropped and the digits are grouped: fours for most cards, 4-6-5 for Amex, which also has 15 digits and a 4-digit code, and the live card and the code field change to match. The expiry gets its slash after the month. The inputs take digits on a phone's numeric keypad and ask the browser for its saved card details with the standard autocomplete values. A test number that passes the checksum, 4242 4242 4242 4242, is offered in the page text; pressing it fills the number with an expiry and a code that pass.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus starts in the card number field and stays inside until it closes, and Escape, Cancel and the close button all return focus to Add card. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The drawn card repeats the fields, so it is hidden from screen readers; each field's hint or message is tied to it with aria-describedby, and one polite status message reports what was added. The copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on Add card.
How does it look on a phone?
The copy shown on load docks to the foot of the page as a bottom sheet, its actions pinned at the bottom with Add card on top, and the fields scroll above them. Below the medium breakpoint the drawn card is left out and the fields take the full width, since they already show what you typed. The real dialog keeps the Dialog's own phone layout, a sheet stuck to the bottom of the screen.
Related
- Pro
Payment Method Billing
Payment and invoicesPayment methods in app settings: the card on file with an expiry warning, a backup bank account, a button that sets the default, and a dialog that checks and updates the card.
- Pro
Billing Address Dialog
Payments and plansAn invoice page with its billing-address dialog shown open: the form relabels, reorders and revalidates for the United States, the United Kingdom, Germany and Japan, a switch fills the company's address, and the address is printed the way an envelope would carry it.
- Pro
Payment Method Dialog
Payments and plansA ticket shop's order summary with its payment-method dialog shown open: a saved card, a bank transfer and an invoice as rows, each asking only for the one detail it needs, and a Pay with row behind the dialog that changes when you choose.
- Pro
Apply Coupon Dialog
Payments and plansA cookware shop's basket with its promo-code dialog shown open: one field that judges five typed codes with five different answers, applied codes kept as removable chips, and a summary that is worked out again after every change.
- Pro
Gift Card Dialog
Payments and plansA café's gift cards page with its builder dialog shown open: a card drawn in greys that reads as you build it, preset or custom amounts, three printed patterns, a recipient and a message, and delivery now or on a day picked in an inline calendar.
- Pro
Add to Cart Dialog
Payments and plansA stool shop's product page with its add-to-cart dialog shown open: two heights that redraw the stool and move the price, three finishes with a sentence each, a quantity that stops at the stock left, and a total that follows the choices.