shadcn.io is not affiliated with official shadcn/ui
Single Page Checkout Block for Svelte
A whole checkout on one page: Contact, Delivery and Payment sections with a sticky index whose anchors show Done or To do from the fields, and one Pay button that names the sections still to finish.
Installation
Overview
Put the whole checkout on one page and keep the buyer oriented, with this single-page checkout for Svelte with Ark UI. A compact header from Eveline, a small skincare maker, sits over one hairline panel in two cells. The main cell stacks three sections, Contact, Delivery and Payment, each under its own heading and rule, with Fields that carry real rules: a valid email, a phone number that is empty or 7 to 15 digits, a name, a street with its number, a city, a two-letter state, a five-digit ZIP, and a card built from Input Group that checks the brand and the Luhn sum. The side cell stays in view and holds an index of the sections. Each entry is an anchor that moves focus to its section's heading and shows a tick and "Done" or a dash and "To do", worked out from the fields themselves, with the order adding up in whole cents below it. A Native Select chooses standard or express delivery and the total follows. Pay is the one Shine Button, in a foot that stays in view. It's built from Field, Input, Native Select, Input Group, Button, Shine Button and Guides, with a CSS entrance only. For short carts, repeat buyers and any shop where one page converts better than a wizard.
FAQ
How does the index know a section is done?
It does not keep a flag; it asks the fields. Contact is done when the email is valid and the phone is empty or valid, Delivery when the name, street, city, state and ZIP all pass, and Payment when the card number, expiry and CVC check out. Editing a field can take a section back to To do at once, and the count above the index ("2 of 3 done") follows.
Why do the index links move focus instead of scrolling?
Because focus is what a keyboard or screen reader user needs. Each link is a real anchor with a hash, but its handler stops the jump and focuses the section's heading, which scrolls it into view and announces where you are. Tab order stays the reading order: the index, then the sections, then the foot.
What happens when I press Pay with sections unfinished?
The button is never disabled. The status line says how many sections are left ("Not paid: 2 sections to finish."), every problem shows under its field, and focus goes to the first wrong field in reading order. A press with everything correct waits 700 milliseconds at the button's normal size and then says it was paid in this demo.
What changes on a phone?
The index becomes a row of three anchors above the form, scrolling sideways if it must, and the order summary is left to the Pay button, which carries the total and is pinned to the bottom of the screen. Fields go full width and the state and ZIP stay on their own lines.
Can I use the card fields for real payments?
No. The card is checked in the tab's memory so you can see the pattern (brand from the first digits, the Luhn sum, the expiry against a fixed month). A real page never lets card digits reach its own code and uses the fields your payment provider hosts. Autocomplete is off in the demo. The test card is 4242 4242 4242 4242 with any future expiry, and Use the test card fills it.
What stays local, and how do I connect it for real?
Everything. The items, the tax rate and the two delivery prices are typed in the file and nothing is sent. To connect it, load the cart from your API, price delivery and tax on your server when the ZIP and the choice change, mount your provider's hosted card fields in Payment, and have Pay create the order with the provider's token.