shadcn.io is not affiliated with official shadcn/ui
Mobile Optimized Checkout Block for React Aria
A sneaker shop's checkout drawn at phone size inside its own scrolling frame: wallet buttons, a folded order summary, 44 px fields that name the keyboard they ask for, and a bottom bar with the total and Pay.
Installation
Overview
Check a checkout against the rules that matter on a phone, with this mobile-optimized checkout for React with React Aria. A header from Garnet Hollow, a sneaker shop, sits over a hairline frame with a plus mark on each corner. In the frame a stage holds a rounded phone-shaped checkout that scrolls on its own, never the page. It opens with two wallet buttons, then an order summary that starts folded as one row ("Order summary, $64.00", a Collapsible) and opens to the lines and shipping. The fields are Inputs 44 px tall, and each names the keyboard it asks for from its type and inputMode: "Email keyboard", "Phone keypad", "Numeric keypad". Card number, expiry and CVC are formatted as you type and checked (brand, Luhn sum, expiry). The bar at the bottom of the frame holds the total and the one Shine Button, Pay $64.00. A press with problems names each one under its field and moves focus to the first. A list under the stage states the rules the frame follows. For mobile checkouts, design reviews and teams who want a starting point that already does the basics.
FAQ
How does a field ask for the right keyboard?
Through two attributes the browser reads: type (email shows an email keyboard) and inputMode (numeric shows a number pad, tel a phone pad). The small label above each field reads them back so you can see which one applies. Phone numbers use inputMode="tel" and ZIP codes and card parts inputMode="numeric" because they are digits but not quantities, and card fields keep autoComplete off in the demo.
Why does the frame scroll, not the page?
So the bottom bar can stay fixed inside it, the way a real phone checkout keeps Pay in reach, while the rest of the page scrolls normally. The scroll region inside the frame is focusable with a visible ring, so a keyboard user can scroll it with the arrow keys. On a real phone you would not draw a frame: the same form and bar would simply fill the screen.
Do the wallet buttons work?
No: pressing one says "No wallet opens in this demo." In your app they would start the platform's payment sheet, which returns the address and a payment token, after which the rest of the form can be skipped. They sit first because they save the most typing.
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, with this layout, labels and error wording around them and the real autocomplete tokens (cc-number, cc-exp, cc-csc, cc-name) that those fields set themselves. Autocomplete is off in the demo so a browser never offers a real saved card to it. Test card 4242 4242 4242 4242 passes with any future expiry (checked against October 2026); a number that fails the Luhn sum, a past expiry or a CVC of the wrong length says so under the field.
What stays local, and how do I connect it for real?
Everything: Pay waits 700 ms, the card digits are cleared once it answers and only the brand and last four stay. To connect it, mount your provider's hosted card fields in the card fields' place (keep the 44 px height and the labels), send the order with their token, and show their error in the same status line.