Adapted from the WM e-commerce checkout. Redesigned for dumpster rental: one-time purchase, single product, no account. Every element justifies its existence or gets cut.
What we know vs. don't know at each entry point. Tier pre-selected, address unknown, geo context available.
Context matrixExposed range calendar, tier toggle (when applicable), address + service area check. Three complexity variants: 1-tier, 2-tier, quote-only.
Range calendar 3 variantsSingle page. Placement + contact + payment. Sticky sidebar. No progress bar, no "What's Included" lists, no trust badge icons.
Less is moreToken-based tracking. 3-step timeline (not 6). Email notice. Done.
Token trackingRange calendar on mobile. Floating price bar + bottom sheet. Single column checkout.
Bottom sheet| Element | V1 Had It | V2 Verdict | Why |
|---|---|---|---|
| Progress bar (3 steps) | Yes | Cut | Flow is dialog → checkout → done. User knows where they are. The back link is enough. |
| "What's Included" list | Yes | Cut | "Delivery to your address" and "Pickup when you're done" are obvious. Patronizing. |
| Trust badge icons | Yes | Cut | Earned by the transaction itself, not clip-art. Cancellation policy does the work. |
| Surface type icon grid | Yes | Cut | Dropdown. 6 emoji icons for surface types is decoration, not information. |
| 6-step timeline | Yes | Cut to 3 | "Fill It Up" and "Hauler Reviews Your Order" are not actionable. Keep: confirmed, delivery, pickup. |
| Container emoji icon box | Yes | Cut | They just clicked a product card. They know it's a dumpster. |
| Waste stream in summary | Yes | Cut | "Household Junk (MSW)" is hauler nomenclature. Customer thinks "20 yard dumpster." |
| Separate gate code field | Yes | Merged | Folded into "Driver notes" with access notes + special instructions. One field, not three. |
| $0 delivery / $0 pickup rows | Yes | Cut | Showing "$0 Free" is marketing copy. Only show fees that aren't zero. |
| Hauler avatar circle | Yes | Cut | No hauler photos exist. A gray circle with initials adds nothing. |
| Sticky sidebar | Yes | Kept | Always-visible pricing is the #1 anxiety reducer in checkout. |
| Overage disclosure | Yes | Kept | The one thing that can surprise the customer. Must be prominent. |
| Cancellation policy | Yes | Kept | Reduces booking anxiety for a $400+ commitment. |
| Range calendar | No (date input) | Added | Exposed calendar visualizes the rental period. Better UX than a date input. |
What we already know when the customer clicks "Book Online" — and what changes based on how they got here.
| Data | Status | Source |
|---|---|---|
| Hauler (name, slug, rating, phone) | Known | Parent page props |
| Product (container, waste stream) | Known | ProductCard the user clicked from |
| Tier (days, price, tonnage, fees) | Known | TierRow "Book Online" button passes tierId |
| Scheduling mode (flexible/fixed) | Known | Product attribute |
| Lead time | Known | Product attribute (leadTimeDays) |
| Delivery address | Unknown | Collected in dialog |
| Geo context (city/state) | Partial | Directory URL if they came from /dumpster-rental/austin-tx |
| Dates | Unknown | Selected via range calendar in dialog |
| Customer identity | Unknown | Collected at checkout (no auth) |
product-catalog.tsx has its own "Book Online" button that passes (productId, tierId). The dialog doesn't need tier selection for the common case (1 tier). It only needs a tier toggle when the product has 2+ tiers AND we want to let users switch without going back.
| Variant | Frequency | Dialog Behavior |
|---|---|---|
| 1 tier | Most common | No tier selection. Calendar + address + price. Simplest flow. |
| 2 tiers | Common | Tier toggle at top of dialog. Pre-selects the tier they clicked. Calendar range updates on switch. |
| 3+ tiers | Edge case | Same as 2-tier but toggle wraps. Still functional. Not optimized for — it's rare. |
| Quote only (no Stripe / mustCall) |
Varies | No "Book Online" button exists. CTA is "Request Quote" or "Call for Pricing." Different flow entirely. |
| Entry Path | Address State | Dialog Behavior |
|---|---|---|
| Direct to hauler profile | Empty | Address field empty. Full input required. |
From city directory page/dumpster-rental/austin-tx |
City known | Could pre-fill city/state. User still enters street. Service area likely valid. |
| From product detail page (same hauler, different tier) |
Previous entry | If user previously entered address in this session (sessionStorage), pre-fill it. |
| Future: address-first search | Full address | Pre-filled and validated. Skip to calendar. Show "Change" link. |
Exposed range calendar. Tier toggle only when relevant. Address with inline service area validation.
No dialog opens. The product card shows different CTAs:
tel: linkThese paths already work in product-catalog.tsx. No wireframe needed — different flow entirely.
Single page. Three sections + sidebar. Every field collects data we need. Nothing decorative.
placementParts.join(" | ") in current checkout-form.tsx). Three inputs for one data point is noise.
PriceBreakdownPanel already does this. No "$0 Free" marketing lines. If delivery is included, it's included — don't list it.
Token-based tracking. Three timeline steps. No noise.
Your 20 yd dumpster with Lone Star Hauling is scheduled.
Payment processed. You're all set.
We'll text you the day before and when the driver is en route.
Dumpster picked up and weighed. If over 3 tons, overage appears on your tracking page.
Range calendar works at 375px. Floating price bar + bottom sheet. Single column.
RangeCalendar handles this responsively.