shadcn.io is not affiliated with official shadcn/ui
Credit Card Field Form Block for Radix UI
A card as one joined control: number, expiry and CVC in a single group with one focus ring, a brand from the first digits, auto-advance, errors that name the part, and only the brand and last four kept after Save.
Installation
Overview
Take a card with this credit card form for React with Radix UI. A compact header sits over a hairline frame with a plus mark on each corner, in cells on a hairline. The card is one joined control built from Input Group: number, expiry and CVC in a single bordered group with one focus ring around it. The number is grouped as you type (4-4-4-4, or 4-6-5 for Amex), a brand tile and the brand's name appear from the first digits, a complete number moves focus to the expiry and a complete expiry to the CVC, and Backspace on an empty part goes back. The first part that is wrong is named under the group ("Check the card number", "This card has expired", "The CVC has 4 digits on this card"). A name and a postal code follow. Save keeps only the brand and the last four ("Visa ending 4242" with a Vi tile) and wipes every digit. There is no drawn card face. For tipping, donation and payment forms that sit in front of a provider's hosted fields.
FAQ
Can I use this to take real card payments?
No, and the code says so. It checks a card in the tab's memory (brand by the first digits, the Luhn sum, the expiry against a fixed month) so you can see the pattern. A real page never lets card digits reach its own code: it uses the fields your payment provider hosts, an iframe of theirs, and this layout, labels and error wording around them. Nothing here is sent, stored or charged.
Which card works in the demo?
The test number 4242 4242 4242 4242 with any future expiry (the check is against October 2026) and any three digits; the "Use the test card" button fills it. A number that fails the Luhn sum, an expiry in the past, a month above 12 or a CVC of the wrong length each says so under the group and marks that part aria-invalid.
How do auto-advance and the keyboard work?
When the number reaches its brand's length and passes the Luhn sum, focus moves to the expiry; when the expiry has four digits and is valid, to the CVC. Only typing at the end advances, so editing the middle never jumps. Backspace in an empty expiry or CVC goes back to the part before with the caret at its end, and the caret stays with its digits while the number is regrouped. Paste works too: spaces and slashes are ignored.
What does Save keep?
Only the brand and the last four digits: "Visa ending 4242". The number, expiry, CVC, name and postal code are cleared from state, and the form is replaced in place by the saved card with a Replace card button, so the panel never changes height. Replace card returns an empty form.
What stays local, and how do I connect it for real?
Everything: Save says "Saved in this demo. Nothing was sent or charged." To connect it for real, mount your provider's hosted number, expiry and CVC fields in the group's place, keep the name and postal code fields, and send the provider's token, never digits, to your server.