figma guide
Designing shopping cart and checkout UI in Figma: line items, totals, and handoff
Design cart drawers, line items, quantity steppers, promo codes, and checkout steps in Figma with variants, empty states, and Dev Mode specs for ecommerce flows.
- Published
- Updated
- Jun 17, 2026
- Read time
- 7 min
- Level
- Beginner
Quick answer
Cart and checkout UI spans three surfaces: mini-cart or drawer (quick edit), full cart page (review), and stepped checkout (shipping → payment → confirm)—each reuses the same LineItem and OrderSummary components. Build LineItem with thumbnail, title, variant text, price, quantity stepper, and remove action; wrap items in CartPanel with sticky OrderSummary (subtotal, discounts, shipping, tax, total). Model empty cart, loading, and error states explicitly. Pair with forms, modals, and progress steppers. Start from the Figma guides hub.
Who this is for
- Product designers shipping DTC stores, marketplaces, and subscription checkout.
- Design system teams aligning cart density across web and mobile breakpoints.
- Engineers implementing quantity limits, promo validation, tax/shipping APIs, and payment element slots.
Cart and checkout surfaces
| Surface | Goal | Key components |
|---|---|---|
| Mini-cart / drawer | Fast review without leaving browse | CartDrawer, LineItem compact |
| Full cart page | Edit quantities, apply promos | CartPage, LineItem full, PromoField |
| Checkout steps | Collect shipping + payment | CheckoutStep, OrderSummary sticky |
| Order confirmation | Receipt + next actions | ConfirmationCard, read-only summary |
| Abandoned cart email | Recovery (marketing) | Static mock—link to live components |
Verdict: one LineItem component with density=compact | comfortable beats separate drawer and page components that drift apart after the first sprint.
LineItem anatomy
| Part | Purpose | Spec tip |
|---|---|---|
| Thumbnail | Product image | 64–80px square; export @2x |
| Title | Product name | 2-line clamp max |
| Variant | Size, color, SKU | text/secondary 14px |
| Unit price | Per-item price | sm PriceDisplay |
| Line total | qty × price | md, right-aligned |
| Quantity | Stepper or input | Min 1, max stock |
| Remove | Icon button or link | Confirm on expensive items optional |
LineItem
├── Variant: density=compact | comfortable
├── Variant: state=default | disabled | error
├── Property: quantity (number)
├── Property: maxQuantity (number optional)
└── Layers:
├── Thumbnail
├── Details (title + variant)
├── PriceColumn (unit + line total)
└── Actions (qty + remove)
Use horizontal auto layout with fixed thumbnail width; let title wrap in the flexible column.
Quantity controls
| Control | Best for | States |
|---|---|---|
| Stepper (− / +) | Most carts | default, min disabled, max disabled |
| Numeric input | B2B bulk orders | focus, error (exceeds stock) |
| Dropdown | Low max (1–5) | Rare—use dropdown |
| State | Visual | Copy |
|---|---|---|
| Default | Enabled stepper | — |
| Min reached | − disabled | — |
| Max stock | + disabled | ”Only 3 left” |
| Error | Red border on input | ”Maximum quantity exceeded” |
| Updating | Skeleton on line total | Optimistic UI note |
Prototype stepper with interactive components swapping quantity property—production debounces API updates.
OrderSummary block
| Row | Order | Notes |
|---|---|---|
| Subtotal | 1 | Sum of line totals |
| Discount / promo | 2 | Negative amount; green optional |
| Shipping | 3 | ”Calculated at next step” or estimate |
| Tax | 4 | Label jurisdiction if required |
| Total | 5 | Bold, lg price |
| Savings (optional) | 6 | ”You save $12.00” below total |
OrderSummary
├── Variant: sticky=on | off
├── Layer: Rows (auto layout vertical)
├── Layer: Divider
├── Layer: Total row
└── Layer: Primary CTA
Sticky summary on desktop checkout: right column fixed while left scrolls forms. On mobile, summary collapses into accordion or top summary bar—document breakpoint behavior.
Checkout step patterns
| Step | Content | Components |
|---|---|---|
| 1 — Cart review | Line items + promo | CartPage, PromoField |
| 2 — Shipping | Address form, method | AddressForm, shipping radio group |
| 3 — Payment | Card / wallet slot | Payment iframe placeholder frame |
| 4 — Review | Read-only summary + place order | LineItem read-only, legal checkbox |
| Confirmation | Order ID, email sent | Empty-state-style success |
Use progress stepper or breadcrumbs for orientation—stepper for <5 steps, breadcrumbs when users may jump back to cart.
Promo code and gift card
| Element | Placement | States |
|---|---|---|
PromoField | Below line items or in summary | default, applying, success, error |
| Applied promo | Summary row | Code + remove link |
| Gift card | Separate expandable section | Collapsed by default |
| State | UI | Message example |
|---|---|---|
| Default | Text input + Apply button | Placeholder: “Promo code” |
| Applying | Button loading | — |
| Success | Green inline alert | ”SAVE20 applied” |
| Invalid | Error on field | ”Code expired or invalid” |
| Stacking rule | Note in Dev Mode | ”One code per order” |
Do not hide promo behind multiple modals unless fraud requires it—discoverability drives conversion.
Cart drawer vs full page
| Aspect | Drawer | Full page |
|---|---|---|
| Width | 360–420px | Content max-width ~1200px |
| LineItem | compact | comfortable |
| Summary | Subtotal + CTA only | Full OrderSummary |
| Empty state | Centered in drawer | Full viewport |
| CTA | ”Checkout” → checkout | ”Proceed to checkout” |
| Close | X or overlay click | N/A |
Show item count badge on cart icon in navigation—badge component with count property max 9+.
Empty, loading, and error states
| State | Drawer | Cart page |
|---|---|---|
| Empty | Illustration + “Your cart is empty” + shop CTA | Same + category links |
| Loading | Skeleton line items × 2 | Full page skeleton |
| Item unavailable | LineItem state=error + remove suggestion | Strike item + notify |
| Checkout error | Toast or top banner | ”Payment failed—try again” |
| Session expired | Modal redirect login | Preserve cart note |
Reuse empty state patterns—do not leave a blank drawer.
Accessibility requirements
| Requirement | Implementation |
|---|---|
| Cart icon | aria-label="Cart, 3 items" |
| Quantity stepper | aria-live="polite" on line total update |
| Remove | Confirm dialog for high-value optional; focus trap in modal |
| Promo error | aria-describedby on input |
| Total change | Announce after promo applied |
| Keyboard | Tab through line items; stepper buttons focusable |
Run accessibility plugins on error red and disabled stepper grays.
Handoff to engineering
| Deliverable | Type | Notes |
|---|---|---|
lineItems[] | array | id, title, variant, qty, unitPrice, imageUrl |
summary | object | subtotal, discount, shipping, tax, total |
currency | ISO code | Same as price component |
promoCode | string optional | Validated server-side |
onQuantityChange | callback | Debounce 300ms typical |
onRemove | callback | — |
checkoutStep | enum | cart | shipping | payment | review |
paymentSlot | frame name | #payment-element mount point |
Publish Patterns / Commerce / Cart in your team library. Payment UI is often iframe-hosted—draw a labeled placeholder frame with min height 200px. Link Dev Mode checklist.
Real-world examples
Fashion DTC drawer
Compact LineItem × 2, subtotal $118.00, primary “Checkout”. Free shipping progress bar: “Add $32 for free shipping” using progress indicator below items.
Marketplace full cart
Comfortable rows with seller grouping subheaders. Promo field expanded. Sticky summary on desktop; mobile floating bar with total + checkout.
Subscription checkout
Single plan LineItem (no thumbnail), annual toggle from segmented control, payment step with Apple Pay + card tabs.
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Different line item in drawer vs page | Visual drift | One component, density variant |
| No empty cart state | Confusing zero state | Dedicated empty state |
| Tax shown before address | Wrong totals | ”Calculated at checkout” placeholder |
| Tiny tap targets on stepper | Mobile frustration | 44×44px min touch |
| Remove without undo | Accidental loss | Toast with undo 5s |
| Promo success without summary row | User doubts discount | Show negative line in summary |
| Payment as static card UI | PCI mismatch | Placeholder frame for provider |
| No loading on qty change | Feels broken | Skeleton line total |
| Cart badge missing on nav | Users forget items | Badge on icon |
| Checkout without step indicator | Anxiety | Stepper or breadcrumbs |
FAQ
Drawer or dedicated cart page first?
Both for serious ecommerce—drawer for speed, page for promo and cross-sell. Share components.
Show product ratings in cart?
Usually no—reduces scan speed. OK on upsell rows below summary.
Guest checkout?
Design email-first step without forcing account creation; account creation optional on confirmation.
Mobile sticky checkout bar?
Yes when summary scrolls off-screen—show total + CTA fixed bottom; document safe area for notched phones per mobile frames guide.
Bottom line
Reuse LineItem and OrderSummary across drawer, cart page, and checkout so quantity, pricing, and promo behavior stay consistent end to end. Model empty, loading, and payment placeholder states up front—cart is where trust breaks if totals lag or discounts disappear. Continue with pricing UI, forms, tables, and the tutorials hub.
§ Keep reading