shadcn.io is not affiliated with official shadcn/ui
Payment Method Onboarding Block for Radix UI
An onboarding screen with card number, expiry, CVC and name fields that format as you type and check the Luhn sum, beside a drawn greyscale card that shows the masked number and name and a Looks valid line in words.
Installation
Overview
Let people add a card and watch it take shape, with this payment step for React with Radix UI. It's the fourth step of Tabwick, a point-of-sale app: the page's side rails run its full height and one band crosses the screen between two rules, split in two. The first half has the step header (the product's mark, “Step 4 of 5” and a hairline of progress), the heading and four Fields with Inputs: the number grouped as you type, the expiry, the CVC and the name. A line says in words whether the card “Looks valid” or what is still needed, and the test number is named as a test number. The second half is a drawn greyscale card showing the brand, the masked number, the name and the expiry. Save card is the only colored control, a Shine Button, and waits for a valid card. Nothing is stored or charged.
FAQ
What is checked, and when?
The number is grouped as you type (4-4-4-4, or 4-6-5 for Amex), must be the brand's length and pass the Luhn sum; the expiry must be a real month in the future; the CVC must have the digits the brand uses; the name needs two characters. A field is checked when you leave it, and all of them when you press Save card, which focuses the first problem. Problems sit in a reserved line, so nothing moves.
Why is the expiry compared with a fixed month?
So everyone reads the same result. It is compared with a typed AS_OF day, never with the clock, which is why an expiry in a past year is refused. In your app the check belongs to the payment provider.
Is this how I should take cards?
No. A real page never lets card digits reach its own code: it uses the fields your payment provider hosts, an iframe of theirs inside this layout, and keeps the drawn card, the step header and the primary button. This block keeps the digits in the tab's memory only to show the pattern, turns browser autofill off so a real saved card is never offered to a demo, and drops every digit when Save card succeeds.
What does the drawn card show?
The brand's two letters once the first digit says which brand it is, a bullet for every digit typed and a dot for every digit still to type, the last four digits only when the number is complete, the name in capitals and the expiry. After Save card it keeps showing the brand and last four that were kept. It is greyscale and hidden from screen readers, which hear the fields and the Looks valid line instead.