takescake

Cart UX Improvements: Receipt-Style Layout and Clickable Card Images

2025-10-05

Cart UX Improvements: Receipt-Style Layout and Clickable Card Images

We've implemented two key UX improvements to the scan cart that make it more intuitive and functional for users browsing their scanned cards.

What Changed

1. Receipt-Style Vertical Expansion

Problem: Cart items were trapped in a fixed-height container with scrolling, making it hard to see your full cart at a glance.

Solution: Removed the maxHeight constraint and overflowY: auto styling. The cart now expands vertically like a receipt, showing all items without internal scrolling.

Impact:

  • Better visibility: See your entire cart at once
  • Natural scrolling: Page scrolls naturally instead of nested scroll containers
  • Mobile-friendly: Easier to browse on phones without dealing with tiny scroll areas
  • Receipt metaphor: Matches the mental model of a physical receipt that gets longer as you add items

2. Clickable Card Images with Correct Art Variant

Problem: Card images in the cart were purely decorative - clicking them did nothing. Users couldn't easily navigate to card detail pages to learn more about cards they'd scanned.

Solution:

  • Wrapped card images in clickable links that navigate to /cards/{oracle_id}?art={card_id}
  • Passes the specific printing ID via ?art= parameter so the card detail page shows the exact art variant
  • Added stopPropagation() to prevent event bubbling conflicts

Impact:

  • Discovery workflow: Scan cards → browse cart → click to learn more about interesting finds
  • Correct art display: Detail page shows the exact printing you scanned, not a random default
  • Natural interaction: Images look clickable and behave as expected
  • Context preservation: URL parameter ensures social shares/bookmarks preserve the specific art variant

Technical Implementation

Receipt-Style Layout

Before:

<div style={{ 
  display: 'flex', 
  flexDirection: 'column', 
  gap: '1rem', 
  maxHeight: '360px',  // ❌ Fixed height with internal scroll
  overflowY: 'auto' 
}}>

After:

<div style={{ 
  display: 'flex', 
  flexDirection: 'column', 
  gap: '1rem'  // ✅ Natural expansion, no scroll constraint
}}>

Also removed position: sticky from the sidebar container so it flows naturally with page content instead of staying fixed at the top.

Clickable Card Images

Before:

<div style={{
  width: '56px',
  height: '80px',
  borderRadius: '8px',
  overflow: 'hidden',
  background: '#eef2ff',
  flexShrink: 0
}}>
  <img src={item.localImage || item.image} alt={item.name} />
</div>

After:

const cardDetailUrl = item.oracle_id 
  ? `/cards/${item.oracle_id}?art=${item.id}` 
  : `/cards/${item.id}`;

<a
  href={cardDetailUrl}
  style={{
    width: '56px',
    height: '80px',
    borderRadius: '8px',
    overflow: 'hidden',
    background: '#eef2ff',
    flexShrink: 0,
    display: 'block',
    textDecoration: 'none',
    cursor: 'pointer'
  }}
  onClick={(e) => e.stopPropagation()}
>
  <img src={item.localImage || item.image} alt={item.name} />
</a>

ID Structure: Cart items now store two IDs:

  • id: The specific Scryfall print ID (unique to this exact printing)
  • oracle_id: The oracle ID shared across all printings of the same card

We use oracle_id for the base URL (so all prints lead to the same card page) and pass the id as the ?art= parameter to feature that specific printing's artwork.

User Workflows Enabled

Trade Show Price Checking

  1. Scan multiple cards at vendor table
  2. Scroll through cart to see all scanned cards at once (receipt view)
  3. Click interesting cards to see all printings, legality, and detailed pricing
  4. Return to cart and continue scanning

Collection Discovery

  1. Scan cards from binder to track inventory
  2. Browse cart and spot cards you want to learn more about
  3. Click card images to explore similar cards, combos, deck ideas
  4. Add to cart from related cards shown on detail page

Budget Planning

  1. Scan wishlist cards from deck list
  2. See total price in expanded cart view
  3. Click cards to compare alternate printings and cheaper versions
  4. Update cart with budget alternatives

Mobile Experience

Both improvements particularly benefit mobile users:

  • Receipt layout: No tiny scroll area - just natural page scrolling
  • Clickable cards: Large touch targets (56×80px) easy to tap
  • Context preservation: Back button returns to cart after viewing details
  • Fast navigation: Jump between cart and detail pages without losing place

Performance Considerations

  • No layout shift: Images maintain fixed size, no CLS when clicking
  • Event delegation: stopPropagation() prevents conflicts with parent handlers
  • URL parameters: Lightweight art variant tracking without extra API calls
  • Client-side navigation: Next.js Link behavior for instant page transitions

Implementation Notes

Why Remove Sticky Positioning?

Original cart used position: sticky to keep it visible while scrolling the page. With receipt-style expansion, this creates UX problems:

  • Long carts: Can't see bottom items without internal scrolling
  • Layout conflicts: Sticky + scrolling parent = confusing behavior
  • Mobile: Sticky sidebars don't work well on small screens

Solution: Let the cart flow naturally with page content. Users can scroll the entire page to see full cart.

Why Store Both IDs?

Cart items now explicitly store two separate IDs:

Print ID (id):

  • The specific Scryfall ID for this exact printing
  • Example: 60b53d4e-56cb-4433-b8b5-5e67e5258dd5
  • Unique to this set/collector number/finish combination
  • Used for ?art= parameter to show correct artwork

Oracle ID (oracle_id):

  • The shared identifier across all printings of the same card
  • Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
  • Same for Secret Lair, regular set, promo versions, etc.
  • Used for base URL so all prints lead to the same card page

This dual-ID approach ensures:

  1. All printings link to the same canonical card page (SEO-friendly)
  2. The correct artwork variant is featured when you arrive
  3. Users can explore all available printings from one page

Browser Compatibility

  • Modern browsers: Full support for flexbox, anchor styling, URL parameters
  • Event handling: stopPropagation() supported everywhere
  • Image rendering: object-fit: cover for proper aspect ratio
  • No polyfills needed: Pure CSS and standard DOM APIs

Future Enhancements

Hover Preview

  • Quick peek: Hover card image to see larger preview without navigating
  • Smart positioning: Preview appears beside cart, not covering it
  • Touch alternative: Long-press on mobile for preview

Bulk Actions

  • Select multiple: Checkboxes for batch operations
  • Move to wishlist: Save interesting cards for later
  • Export selected: Download subset of cart as CSV/TXT

Printing Comparison

  • Side-by-side: Compare different printings from cart
  • Price differences: Highlight best value options
  • Set indicators: Show which sets have foil/showcase variants

Smart Grouping

  • By deck: Organize cart items by commander/archetype
  • By vendor: Group by which vendor had each card at show
  • By price tier: Budget/mid/premium categories

Testing Checklist

  • Cart expands vertically without height limit
  • Page scrolls naturally with long carts
  • Card images are clearly clickable (cursor, styling)
  • Clicking images navigates to correct card detail page
  • ?art= parameter loads the correct printing variant
  • Back button returns to cart correctly
  • Mobile: images tappable, no layout shift
  • Mobile: scrolling smooth, no nested scroll confusion
  • Social sharing card detail URLs preserve art variant
  • No JavaScript errors in console
  • No layout shift when clicking images

Related Features

Key Takeaway

Small UX improvements compound into better user experiences. Receipt-style layout removes cognitive friction (nested scrolling), while clickable images enable natural discovery workflows (scan → browse → explore). Both changes make the cart feel more responsive and intuitive without adding complexity.

Related Posts