Order Confirmation
blockcommercePost-purchase order confirmation & tracking page featuring a success banner with emerald checkmark halo, 4-step shipment progress bar with pulsing active state, itemized order breakdown, and customer delivery & payment cards.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/order-confirmation.json$npx shadcn@latest add https://uipkge.dev/r/lit/order-confirmation.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/order-confirmation.json$bunx shadcn@latest add https://uipkge.dev/r/lit/order-confirmation.jsonManifest:
https://uipkge.dev/r/lit/order-confirmation.jsonInstalls to:src/uip/blocks/order-confirmation/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
OrderIteminterface OrderItem {
id: string
name: string
variant: string
quantity: number
price: string
image: string
}TrackingStepinterface TrackingStep {
id: string
title: string
date: string
status: 'completed' | 'current' | 'upcoming'
description: string
}HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-order-confirmation': UipOrderConfirmation
}
}Files installed (1)
src/uip/blocks/order-confirmation/order-confirmation.ts18.7 kB
import { LitElement, css, html } from 'lit' import { Check, CheckCircle2, CreditCard, Download, ExternalLink, HelpCircle, Mail, MapPin, MessageSquare, Package, Truck, } from 'lucide' import { cn } from '../../lib/utils' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' import { icon } from '../../lib/icon' // Side-effect imports: register the composed elements for standalone use // (consumers who install only this block still get working primitives). import '../../components/badge/badge' import '../../components/button/button' import '../../components/card/card' import '../../components/separator/separator' interface OrderItem { id: string name: string variant: string quantity: number price: string image: string } interface TrackingStep { id: string title: string date: string status: 'completed' | 'current' | 'upcoming' description: string } const orderItems: OrderItem[] = [ { id: 'item-1', name: 'Studio Wireless Noise-Canceling Headphones', variant: 'Space Gray • Over-Ear', quantity: 1, price: '$179.00', image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=160&auto=format&fit=crop&q=80', }, { id: 'item-2', name: 'Braided USB-C Fast Charging Cable (2m)', variant: 'Midnight Black • 100W PD', quantity: 2, price: '$38.00', image: 'https://images.unsplash.com/photo-1546868871-7041f2a55e12?w=160&auto=format&fit=crop&q=80', }, { id: 'item-3', name: 'Magnetic Aluminum Desk Stand', variant: 'Silver • Anodized Aluminum', quantity: 1, price: '$35.00', image: 'https://images.unsplash.com/photo-1586105251261-72a756497a11?w=160&auto=format&fit=crop&q=80', }, ] const trackingSteps: TrackingStep[] = [ { id: 'step-1', title: 'Order Placed', date: 'Aug 21, 2026 • 10:42 AM', status: 'completed', description: 'Payment authorized & order confirmed', }, { id: 'step-2', title: 'Processing', date: 'Aug 22, 2026 • 02:15 PM', status: 'completed', description: 'Item picked & packed at warehouse', }, { id: 'step-3', title: 'Shipped', date: 'Aug 23, 2026 • 09:30 AM', status: 'current', description: 'In transit via FedEx Priority • Chicago, IL', }, { id: 'step-4', title: 'Delivered', date: 'Est. Aug 27, 2026', status: 'upcoming', description: 'Estimated delivery to front door', }, ] /** * <uip-order-confirmation> — the registry OrderConfirmation block as a web component. * * Class strings and sample data are React's verbatim. The block is fully * static (React holds no state): success banner, desktop + mobile tracking * stepper, itemized summary with cost breakdown, and shipping / payment / * help cards. No props, no events. */ export class UipOrderConfirmation extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: block; }`] constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'order-confirmation') } render() { return html` <div data-slot="order-confirmation" class="w-full space-y-6"> <uip-card class="border shadow-xs"> <uip-card-content class="flex flex-col items-center p-6 text-center sm:p-10"> <div class="bg-success/10 text-success ring-success/10 text-success relative flex size-16 items-center justify-center rounded-full ring-8 sm:size-20" > ${icon(CheckCircle2, 'circle-check', 'size-8 sm:size-10')} </div> <div class="mt-6 max-w-xl space-y-2"> <div class="border-success/20 bg-success/10 text-success inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium" > <span class="bg-success size-1.5 rounded-full"></span> Order Confirmed </div> <h1 class="text-foreground text-2xl font-bold tracking-tight sm:text-3xl">Thank you for your order!</h1> <p class="text-muted-foreground text-sm sm:text-base"> We've received your order <span class="text-foreground font-mono font-semibold">#ORD-92841</span> and sent a confirmation email to <span class="text-foreground font-medium">customer@example.com</span>. </p> </div> <div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <uip-button class="gap-2 shadow-xs"> ${icon(ExternalLink, 'external-link', 'size-4')} Track Shipment </uip-button> <uip-button aria-label="Download attachment" variant="outline" class="gap-2 shadow-xs"> ${icon(Download, 'download', 'size-4')} Download Receipt </uip-button> <uip-button variant="ghost" class="text-muted-foreground hover:text-foreground">Continue Shopping</uip-button> </div> </uip-card-content> </uip-card> <uip-card class="border shadow-xs"> <uip-card-header class="flex flex-col gap-3 pb-4 sm:flex-row sm:items-center sm:justify-between"> <div class="space-y-1"> <div class="flex items-center gap-2"> ${icon(Truck, 'truck', 'text-primary size-4')} <uip-card-title class="text-base font-semibold">Shipment Progress</uip-card-title> <uip-badge variant="secondary" class="bg-primary/10 text-primary text-xs font-medium">In Transit</uip-badge> </div> <p class="text-muted-foreground text-xs"> Carrier: <span class="text-foreground font-medium">FedEx Priority</span> • Tracking: <span class="text-foreground font-mono font-medium">#FX-9821734910</span> </p> </div> <div class="border-border/80 bg-muted/40 rounded-lg border px-3 py-1.5 text-xs"> <span class="text-muted-foreground">Estimated Delivery:</span> <span class="text-foreground ml-1 font-semibold">Thursday, Aug 27, 2026</span> </div> </uip-card-header> <uip-card-content class="pt-4"> <div class="hidden md:block"> <div class="grid grid-cols-4 gap-4"> ${trackingSteps.map( (step, idx) => html`<div class="relative flex flex-col"> <div class="relative flex items-center"> ${idx > 0 ? html`<div class=${cn( 'absolute top-1/2 right-1/2 -z-0 h-0.5 w-full -translate-y-1/2', step.status === 'upcoming' ? 'bg-muted' : 'bg-primary', )} ></div>` : html``} ${idx < trackingSteps.length - 1 ? html`<div class=${cn( 'absolute top-1/2 left-1/2 -z-0 h-0.5 w-full -translate-y-1/2', trackingSteps[idx + 1]?.status === 'upcoming' ? 'bg-muted' : 'bg-primary', )} ></div>` : html``} <div class="relative z-10 mx-auto flex items-center justify-center"> ${step.status === 'completed' ? html`<div class="bg-primary text-primary-foreground ring-background flex size-8 items-center justify-center rounded-full ring-4" > ${icon(Check, 'check', 'size-4')} </div>` : step.status === 'current' ? html`<div class="border-primary bg-background text-primary ring-background flex size-8 items-center justify-center rounded-full border-2 ring-4" > <span class="relative flex size-2.5"> <span class="bg-primary absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="bg-primary relative inline-flex size-2.5 rounded-full"></span> </span> </div>` : html`<div class="border-muted-foreground/30 bg-muted/40 text-muted-foreground ring-background flex size-8 items-center justify-center rounded-full border-2 ring-4" > ${icon(Package, 'package', 'size-3.5')} </div>`} </div> </div> <div class="mt-3 text-center"> <p class=${cn('text-sm font-semibold', step.status === 'upcoming' ? 'text-muted-foreground' : 'text-foreground')}> ${step.title} </p> <p class="text-muted-foreground mt-0.5 text-xs tabular-nums">${step.date}</p> <p class="text-muted-foreground/80 mt-0.5 text-xs">${step.description}</p> </div> </div>`, )} </div> </div> <div class="space-y-4 md:hidden"> ${trackingSteps.map( (step, idx) => html`<div class="flex items-start gap-3"> <div class="flex flex-col items-center"> ${step.status === 'completed' ? html`<div class="bg-primary text-primary-foreground flex size-7 shrink-0 items-center justify-center rounded-full"> ${icon(Check, 'check', 'size-3.5')} </div>` : step.status === 'current' ? html`<div class="border-primary bg-background text-primary flex size-7 shrink-0 items-center justify-center rounded-full border-2" > <span class="relative flex size-2"> <span class="bg-primary absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="bg-primary relative inline-flex size-2 rounded-full"></span> </span> </div>` : html`<div class="border-muted-foreground/30 bg-muted/40 text-muted-foreground flex size-7 shrink-0 items-center justify-center rounded-full border-2" > ${icon(Package, 'package', 'size-3')} </div>`} ${idx < trackingSteps.length - 1 ? html`<div class=${cn( 'mt-1 h-8 w-0.5', trackingSteps[idx + 1]?.status === 'upcoming' ? 'bg-muted' : 'bg-primary', )} ></div>` : html``} </div> <div class="min-w-0 flex-1 pt-0.5 pb-2"> <div class="flex items-center justify-between gap-2"> <p class=${cn('text-sm font-semibold', step.status === 'upcoming' ? 'text-muted-foreground' : 'text-foreground')}> ${step.title} </p> <span class="text-muted-foreground text-xs tabular-nums">${step.date}</span> </div> <p class="text-muted-foreground mt-0.5 text-xs">${step.description}</p> </div> </div>`, )} </div> </uip-card-content> </uip-card> <div class="grid grid-cols-1 gap-6 lg:grid-cols-12"> <div class="lg:col-span-7"> <uip-card class="border shadow-xs"> <uip-card-header class="pb-4"> <uip-card-title class="text-base font-semibold">Order Summary</uip-card-title> <uip-card-description>3 items in shipment</uip-card-description> </uip-card-header> <uip-card-content class="space-y-6"> <div class="space-y-4"> ${orderItems.map( (item) => html`<div class="flex items-center gap-4"> <div class="border-border bg-muted/40 relative size-16 shrink-0 overflow-hidden rounded-lg border"> <img src=${item.image} alt=${item.name} class="h-full w-full object-cover" /> </div> <div class="min-w-0 flex-1"> <p class="text-foreground truncate text-sm font-medium">${item.name}</p> <p class="text-muted-foreground text-xs">${item.variant}</p> <p class="text-muted-foreground mt-1 text-xs">Qty: ${item.quantity}</p> </div> <div class="text-right"> <p class="text-foreground text-sm font-semibold tabular-nums">${item.price}</p> </div> </div>`, )} </div> <uip-separator></uip-separator> <div class="space-y-2 text-sm"> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Subtotal</span> <span class="text-foreground font-medium tabular-nums">$252.00</span> </div> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Shipping (FedEx Priority)</span> <span class="text-success text-success font-medium tabular-nums">Free</span> </div> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Estimated Tax</span> <span class="text-foreground font-medium tabular-nums">$12.50</span> </div> </div> <uip-separator></uip-separator> <div class="flex items-center justify-between"> <span class="text-foreground text-base font-semibold">Total</span> <span class="text-foreground text-xl font-bold tabular-nums sm:text-2xl">$264.50</span> </div> </uip-card-content> </uip-card> </div> <div class="space-y-6 lg:col-span-5"> <uip-card class="border shadow-xs"> <uip-card-header class="pb-3"> <div class="flex items-center gap-2"> ${icon(MapPin, 'map-pin', 'text-muted-foreground size-4')} <uip-card-title class="text-base font-semibold">Shipping Address</uip-card-title> </div> </uip-card-header> <uip-card-content class="space-y-3 text-sm"> <div class="space-y-0.5"> <p class="text-foreground font-medium">Alex Morgan</p> <p class="text-muted-foreground">742 Evergreen Terrace, Suite 4B</p> <p class="text-muted-foreground">Springfield, OR 97477</p> <p class="text-muted-foreground">United States</p> <p class="text-muted-foreground mt-1 text-xs">+1 (555) 234-5678</p> </div> <div class="border-border bg-muted/30 rounded-md border p-2.5 text-xs"> <span class="text-muted-foreground">Delivery Method:</span> <span class="text-foreground ml-1 font-medium">FedEx Priority Express</span> </div> </uip-card-content> </uip-card> <uip-card class="border shadow-xs"> <uip-card-header class="pb-3"> <div class="flex items-center gap-2"> ${icon(CreditCard, 'credit-card', 'text-muted-foreground size-4')} <uip-card-title class="text-base font-semibold">Payment Method</uip-card-title> </div> </uip-card-header> <uip-card-content class="space-y-3 text-sm"> <div class="flex items-center justify-between"> <div class="flex items-center gap-2.5"> <div class="border-border bg-muted/40 text-foreground flex h-7 w-11 items-center justify-center rounded border font-mono text-xs font-bold"> VISA </div> <div> <p class="text-foreground text-sm font-medium">Visa ending in 4242</p> <p class="text-muted-foreground text-xs">Expires 08/29</p> </div> </div> <uip-badge variant="secondary" class="bg-success/10 text-success">Paid</uip-badge> </div> <p class="text-muted-foreground text-xs">Billing address matches shipping address</p> </uip-card-content> </uip-card> <uip-card class="border shadow-xs"> <uip-card-header class="pb-3"> <div class="flex items-center gap-2"> ${icon(HelpCircle, 'circle-help', 'text-muted-foreground size-4')} <uip-card-title class="text-base font-semibold">Need Help?</uip-card-title> </div> </uip-card-header> <uip-card-content class="space-y-3 text-sm"> <p class="text-muted-foreground text-xs">Questions about your order? Chat with support or email support@example.com.</p> <div class="space-y-2 pt-1"> <uip-button variant="outline" size="sm" class="w-full justify-start gap-2 text-xs shadow-xs"> ${icon(MessageSquare, 'message-square', 'size-3.5')} Chat with Support </uip-button> <uip-button variant="ghost" size="sm" class="text-muted-foreground hover:text-foreground w-full justify-start gap-2 text-xs"> ${icon(Mail, 'mail', 'size-3.5')} support@example.com </uip-button> </div> </uip-card-content> </uip-card> </div> </div> </div> ` } } customElements.get('uip-order-confirmation') || customElements.define('uip-order-confirmation', UipOrderConfirmation) declare global { interface HTMLElementTagNameMap { 'uip-order-confirmation': UipOrderConfirmation } }
Raw manifest:https://uipkge.dev/r/lit/order-confirmation.json