shadcn.io is not affiliated with official shadcn/ui
Age Verification Checkout Block for Svelte
An order with a spirits line, checked against a fixed date: a date of birth that says how old you are on that day and whether it meets 21, then two ways to meet the rule at hand-over, adult signature or collection with ID, that re-price shipping, the arrival date and the total.
Installation
Overview
Handle a restricted product at checkout, with this age verification for Svelte with Ark UI. A compact header from Vintry, a wine and spirits merchant, states the rule: spirits are for people 21 and over. The first band is a date of birth in a Field with a date Input; it is checked against a fixed date (18 October 2026, never the visitor's clock) with the years worked out from the date parts, and it says "Age 36 on Sun 18 Oct 2026: meets the 21 rule" or how old you are and what the order needs. Below it two native radio cards say how the rule is met at hand-over: adult signature on delivery with ID shown (plus $4.50 and a day more) or collection in store with ID (free, ready sooner). The name-on-ID field is for the first choice only and must match the name on the order. The order's lines, the shipping line, the arrival or ready date and the total re-derive from the choice in whole cents. Continue to payment is the only Shine Button; it names the first thing in the way and focuses it. It's built from Field, Input, Guides and native radios. For alcohol, tobacco, knives and any regulated product.
FAQ
How is the age worked out?
From the ISO date parts, not from Date arithmetic on the visitor's clock: years between the two years, minus one if the birthday has not come round on the fixed day (AS_OF). That is why the same input gives the same answer on the server and in the browser. Change AS_OF and MIN_AGE for your market; in your app the day comes from your server.
Does it verify anyone?
No. A date of birth anyone can type proves nothing, so the block treats it as a declaration and moves the real check to hand-over: the courier or the counter sees the ID, and only the named person can sign. Nothing is stored or sent in the demo. Where the law requires verification before purchase, call your identity provider from the same Continue step.
What changes when I switch how the rule is met?
The shipping line, the date and the total, all from one lookup: signature costs the base shipping plus $4.50 and adds two days; collection is free and ready after 2 pm. Dates are written from the fixed day with UTC parts, so they don't depend on the visitor's time zone. The name-on-ID field stays in place but is disabled for collection, so nothing shifts.
What happens under age?
The field's own line says "You are 19. The spirits in this order need 21 or over." as you type, the field is marked invalid, and Continue to payment says it did not continue and returns focus to the date. The button is never disabled, so the reason is always one press away.
Does it work right to left?
Yes. Names, dates and notes sit in isolates, prices are forced left to right, and the radio cards use logical sides. The native date field follows the browser's own locale and direction.
What stays local in the demo, and how do I wire it up?
Everything. The date and name live in the block's state, and Continue to payment only says that payment comes next. In your app keep the declaration with the order, tell your carrier which parcels need an adult signature, and store the ID check result at hand-over. To go to your payment step: wrap an a element in the Shine Button with asChild.