shadcn.io is not affiliated with official shadcn/ui
Event Tickets Checkout Block for Ark UI
A ticket per person priced by type: up to six rows with an attendee name and Adult, Child or Concession, a family rule that takes $4 off every two adults and two children, booking fees and a total worked out in cents.
Installation
Overview
Sell tickets one person at a time, with this event-tickets checkout for React with Ark UI. A compact header from Hobby and Hare, a small live-music venue, names the night and its doors time. In a hairline frame with a plus mark on each corner, a buyer name and email come first, then a roster of up to six tickets: each row has an attendee Input, a type Native Select (Adult $28, Child $12, Concession $20), its price and a Remove named for the ticket, and the first row has a "Same as buyer" Checkbox. Add a ticket puts a new row in the roster and moves focus into its name. A family rule is worked out from the roster, not asked for: every two adults and two children together pay $76 instead of $80, and the saving appears as its own line the moment the roster matches. Booking fees are $2.50 a ticket, and the subtotal, the saving, the fees and the total are all whole cents. Pay is the only Shine Button. It's built from Input, Native Select, Checkbox, Field, Button, Shine Button and Guides, with a CSS entrance only. For events, classes and anything sold per person.
FAQ
How does the family rule work?
It counts the adults and the children in the roster and pairs them: each two adults plus two children is one family, and each family is charged $76.00 instead of the $80.00 the four tickets add up to, a $4.00 saving. Four adults and four children make two families and an $8.00 saving; one adult and three children make none. The rule is one small helper (familiesOf), so changing the price or the pairing is a one-line edit.
How are the fees and the total worked out?
Every figure is an integer number of cents. The subtotal adds each ticket's price from the TYPES table, the family saving is subtracted, and the booking fee is FEE cents for each ticket. The total is derived from the roster on every render, so no number is typed twice, and usd is the only place cents become dollars.
Do I pick seats?
No: seats are assigned at the venue, and the status line says so before you pay. If your event has numbered seats, put a seating chart in the step before this one and carry the chosen seats into the roster rows.
What happens when I press Pay with names missing?
The button is never disabled. A press marks the buyer's name, the email and every attendee name that is empty (a name borrowed from the buyer counts), says "Not paid" in the polite status line and moves focus to the first one in reading order. Each field has a reserved line for its problem, so rows don't jump. Removing a ticket, adding one and ticking Same as buyer each say what changed in the status line.
How does the roster look on a phone?
Each ticket becomes a small card: the attendee field full width, then the type select with Remove beside it, with the price shown inside the select's option text ("Adult, $28.00"). From the medium breakpoint the rows line up under column heads for attendee, type and price. The first ticket has no Remove, so a booking always holds at least one ticket.
What stays local in the demo, and how do I wire it up?
Everything. The roster, the buyer and the total live in the block's state, nothing is held or sold, and Pay only waits 700 ms and says that nothing was charged. In your app, check availability on your server when the roster changes, hold the tickets for a few minutes while the visitor pays, and recompute the total there: treat this figure as a preview.