Live preview
Walk through the steps. Try the promo code WELCOME10
for 10% off, or SHIPFREE for free shipping; switch
shipping methods to watch totals recompute; then place the order to
see the confirmation screen.
$step = "info"
$email = "ada@compute.lab"
$firstName = "Ada"
$lastName = "Lovelace"
$phone = ""
$address1 = ""
$address2 = ""
$city = ""
$region = ""
$zip = ""
$country = "us"
$shipMethod = "standard"
$payMethod = "card"
$cardName = ""
$cardNumber = ""
$cardExp = ""
$cardCvc = ""
$promo = ""
$promoApplied = ""
$saveAddress = true
$marketing = false
$cart = [
{id: "tee", title: "Streaming UI tee", variant: "Heather grey · M", qty: 2, price: 32.00},
{id: "mug", title: "Generative UI mug", variant: "12oz · Indigo", qty: 1, price: 18.00},
{id: "sticker", title: "Pattern composites pack", variant: "20 stickers · Vinyl", qty: 3, price: 6.00}
]
ship = Query("ship_quote", {country: $country, method: $shipMethod}, {price: 0, eta: ""})
lineTotals = @Each($cart, "c", c.price * c.qty)
quantities = @Each($cart, "c", c.qty)
subtotal = @Sum(lineTotals)
itemCount = @Sum(quantities)
discount = $promoApplied == "WELCOME10" ? @Round(subtotal * 0.1, 2) : 0
shippingPrice = $promoApplied == "SHIPFREE" ? 0 : ship.price
total = @Round(subtotal - discount + shippingPrice, 2)
stepIndex = $step == "info" ? 0 : ($step == "shipping" ? 1 : ($step == "payment" ? 2 : ($step == "review" ? 3 : 4)))
progress = Steps([
StepsItem("Your info", $firstName + " " + $lastName + " · " + $email),
StepsItem("Shipping", $address1 == "" ? "Add address" : ($city + ", " + $region + " · " + ship.eta)),
StepsItem("Payment", $payMethod == "card" ? "Card on file" : ($payMethod == "paypal" ? "PayPal" : "Apple Pay")),
StepsItem("Review", $step == "done" ? "Order placed" : ("Total $" + total))
])
infoCard = Card([
SectionHeader("Your info", "We'll send your receipt and shipping updates here.", "Step 1 of 4"),
Stack([
FormControl("Email", Input("email", "you@company.com", "email", null, $email)),
Grid([
FormControl("First name", Input("firstName", "Ada", "text", null, $firstName)),
FormControl("Last name", Input("lastName", "Lovelace", "text", null, $lastName))
], 2, "m"),
FormControl("Phone (optional)", Input("phone", "+1 555 123 4567", "tel", null, $phone)),
Switch("marketing", "Email me product updates and offers", $marketing, "Unsubscribe anytime, one click.")
], "column", "m"),
Separator("horizontal", true),
Stack([
Button("Back to cart", Action([@ToAssistant("Back to cart")]), "ghost"),
Spacer(),
Button("Continue to shipping",
Action([@Set($step, "shipping")]),
"primary")
], "row", "m", "center")
])
shippingCard = Card([
SectionHeader("Shipping address", "Where should we send the order?", "Step 2 of 4"),
Stack([
FormControl("Country", Combobox("country", [
SelectItem("us", "United States"),
SelectItem("ca", "Canada"),
SelectItem("uk", "United Kingdom"),
SelectItem("de", "Germany"),
SelectItem("fr", "France"),
SelectItem("jp", "Japan"),
SelectItem("au", "Australia")
], $country, "Search country…")),
FormControl("Address line 1", Input("addr1", "1 Market St", "text", null, $address1)),
FormControl("Address line 2 (optional)", Input("addr2", "Apt 4B", "text", null, $address2)),
Grid([
FormControl("City", Input("city", "San Francisco", "text", null, $city)),
FormControl("State/region", Input("region", "CA", "text", null, $region)),
FormControl("Postal code", Input("zip", "94105", "text", null, $zip))
], 3, "m"),
Switch("saveAddress", "Save this address to my account", $saveAddress)
], "column", "m"),
Separator("horizontal", true),
SectionHeader("Shipping method", "Pick a delivery speed.", null, Tag(ship.eta, "truck", "sm", "info")),
Radio("shipMethod", [
SelectItem("standard", "Standard · 5-7 business days"),
SelectItem("express", "Express · 2-3 business days"),
SelectItem("next-day", "Next-day · order before 2pm")
], $shipMethod),
Separator("horizontal", true),
Stack([
Button("Back",
Action([@Set($step, "info")]),
"ghost"),
Spacer(),
Button("Continue to payment",
Action([@Set($step, "payment")]),
"primary")
], "row", "m", "center")
])
cardFields = Stack([
FormControl("Name on card", Input("cardName", "Ada Lovelace", "text", null, $cardName)),
FormControl("Card number", Input("cardNumber", "4242 4242 4242 4242", "text", null, $cardNumber)),
Grid([
FormControl("Expiry", Input("cardExp", "MM / YY", "text", null, $cardExp)),
FormControl("CVC", Input("cardCvc", "123", "text", null, $cardCvc))
], 2, "m"),
Note("Test cards only. We never store card details — payment is tokenised before it leaves the browser.", "info", "lock")
], "column", "m")
paypalPanel = Stack([
Note("You'll be redirected to PayPal to confirm your payment after placing the order.", "info", "paypal"),
Buttons([Button("Continue with PayPal",
Action([@OpenUrl("https://www.paypal.com")]),
"primary")])
], "column", "m")
applePayPanel = Stack([
Note("Apple Pay works on Safari with Touch ID or Face ID. We don't see your card details.", "info", "apple"),
Buttons([Button("Pay with Apple Pay",
Action([@ToAssistant("Trigger Apple Pay")]),
"primary")])
], "column", "m")
paymentBody = $payMethod == "card" ? cardFields : ($payMethod == "paypal" ? paypalPanel : applePayPanel)
paymentCard = Card([
SectionHeader("Payment method", "Pick how you'd like to pay.", "Step 3 of 4"),
Radio("payMethod", [
SelectItem("card", "Credit or debit card"),
SelectItem("paypal", "PayPal"),
SelectItem("applepay", "Apple Pay")
], $payMethod),
Separator("horizontal", true),
paymentBody,
Separator("horizontal", true),
Stack([
Button("Back",
Action([@Set($step, "shipping")]),
"ghost"),
Spacer(),
Button("Review order",
Action([@Set($step, "review")]),
"primary")
], "row", "m", "center")
])
reviewLines = DescriptionList([
DescriptionItem("Contact", $email, "envelope"),
DescriptionItem("Ship to", $firstName + " " + $lastName + " · " + $address1 + " · " + $city + ", " + $region + " " + $zip, "location-dot"),
DescriptionItem("Method", $shipMethod == "standard" ? "Standard · 5-7 days" : ($shipMethod == "express" ? "Express · 2-3 days" : "Next-day · order before 2pm"), "truck"),
DescriptionItem("Payment", $payMethod == "card" ? "Card on file" : ($payMethod == "paypal" ? "PayPal" : "Apple Pay"), "credit-card")
])
reviewItems = Table([
Col("Item", @Each($cart, "c", c.title + " · " + c.variant)),
Col("Qty", @Each($cart, "c", "" + c.qty)),
Col("Price", @Each($cart, "c", "$" + c.price)),
Col("Subtotal", @Each($cart, "c", "$" + (c.price * c.qty)))
])
reviewCard = Card([
SectionHeader("Review order", "Take one last look — you can still edit any section.", "Step 4 of 4"),
reviewLines,
Separator("horizontal", true),
reviewItems,
Separator("horizontal", true),
Stack([
Button("Back",
Action([@Set($step, "payment")]),
"ghost"),
Spacer(),
Button("Edit shipping",
Action([@Set($step, "shipping")]),
"ghost"),
Button("Place order · $" + total,
Action([@Set($step, "done"), @ToAssistant("Place the order for " + $email)]),
"primary")
], "row", "m", "center")
])
doneCard = Card([
Hero(
"Order placed!",
"Order #ACME-2491 — receipt sent to " + $email,
Button("Track shipment", Action([@ToAssistant("Track ACME-2491")]), "primary"),
Button("Back to shop", Action([@ToAssistant("Continue shopping")]), "secondary"),
"Thanks for your order",
null,
null,
"success"
),
Stack([
StatusDot("Authorising payment", "success"),
StatusDot("Reserving inventory", "success"),
StatusDot("Printing label", "warning", true),
StatusDot("Handing off to carrier","default")
], "column", "s"),
DescriptionList([
DescriptionItem("Order ID", "ACME-2491", "hashtag"),
DescriptionItem("Total", "$" + total, "sack-dollar"),
DescriptionItem("Estimated arrival", ship.eta + " · " + ($shipMethod == "next-day" ? "Tomorrow" : ($shipMethod == "express" ? "Tue-Wed" : "Mon-Fri next week")), "calendar"),
DescriptionItem("Confirmation sent", $email, "envelope")
])
])
mainPane = $step == "info" ? infoCard : ($step == "shipping" ? shippingCard : ($step == "payment" ? paymentCard : ($step == "review" ? reviewCard : doneCard)))
cartRows = @Each($cart, "c",
Stack([
Stack([
TextContent(c.title, "small-heavy"),
TextContent(c.variant, "small", "muted"),
TextContent("Qty " + c.qty + " · $" + c.price + " each", "small", "muted")
], "column", "xs"),
Spacer(),
TextContent("$" + (c.price * c.qty), "body-heavy")
], "row", "s", "center")
)
promoNote = $promoApplied == "" ? null : ($promoApplied == "WELCOME10" ? Note("WELCOME10 applied — 10% off your order.", "success", "tags") : ($promoApplied == "SHIPFREE" ? Note("SHIPFREE applied — free shipping.", "success", "truck") : Note("Code \"" + $promoApplied + "\" isn't valid.", "warning", "circle-info")))
orderSummary = Card([
SectionHeader("Order summary", "" + itemCount + " items in cart"),
Stack(cartRows, "column", "m"),
Separator("horizontal", true),
Stack([
FormControl("Promo code", Input("promo", "WELCOME10 or SHIPFREE", "text", null, $promo)),
Button("Apply",
Action([@Set($promoApplied, $promo)]),
"secondary",
"button",
"small")
], "row", "s", "end"),
promoNote,
Separator("horizontal", true),
DescriptionList([
DescriptionItem("Subtotal", "$" + subtotal, "tag"),
DescriptionItem("Shipping", "$" + shippingPrice + " · " + ship.eta, "truck"),
DescriptionItem("Discount", "-$" + discount, "percent"),
DescriptionItem("Total", "$" + total, "sack-dollar")
]),
Note("All prices in USD. Taxes calculated at next step where applicable.", "info", "circle-info")
])
split = $step == "done" ? mainPane : SplitView([mainPane], [orderSummary], "1.5fr")
header = PageHeader(
"Checkout",
"Step " + (stepIndex + 1) + " of 4",
Breadcrumb([BreadcrumbItem("Shop", "#"), BreadcrumbItem("Cart", "#"), BreadcrumbItem("Checkout")]),
[Button("Save & continue later",
Action([@ToAssistant("Save my cart and email me a checkout link")]),
"ghost")],
Badge($step == "done" ? "Complete" : "In progress", $step == "done" ? "success" : "info")
)
trust = Stats([
{label: "Free returns", value: "30 days", hint: "no questions asked", tone: "success"},
{label: "Carbon offset", value: "100%", hint: "every shipment", tone: "info"},
{label: "Support", value: "24 / 7", hint: "live chat", tone: "primary"},
{label: "Secure", value: "TLS 1.3", hint: "PCI-DSS 4.0", tone: "default"}
])
followUps = FollowUpBlock([
FollowUpItem("Apply a promo code"),
FollowUpItem("Change shipping address"),
FollowUpItem("Use a different card")
], "Need help?")
root = Stack([header, progress, trust, split, $step == "done" ? null : followUps], "column", "l")