15 KiB
Product Detail Page Layout
Contents
- Overview
- Layout Structure
- Price Display and Medusa Integration
- Variant Selection (Critical)
- Stock Availability
- Add to Cart Behavior
- Product Details Organization
- Related Products Strategy
- Trust Signals and Conversion
- Mobile Optimization
- Checklist
Overview
Most critical page for conversion. Customers make purchase decisions here based on product information, images, reviews, and trust signals.
Key Requirements
- High-quality product images with zoom capability
- Clear price display (handle variant price changes)
- Variant selection (size, color, material)
- Stock availability indicators
- Prominent "Add to Cart" with proper feedback
- Product details (description, specifications)
- Customer reviews and ratings
- Related product recommendations
- Trust signals (shipping, returns, secure checkout)
- Mobile-optimized (60%+ traffic)
Routing Pattern
CRITICAL: Always use dynamic routes, NEVER static pages.
Product detail pages must use dynamic routes that accept a parameter (handle, slug, or ID):
Correct examples:
- Next.js App Router:
app/products/[handle]/page.tsx - Next.js Pages Router:
pages/products/[handle].tsx - SvelteKit:
routes/products/[handle]/+page.svelte - TanStack Start:
routes/products/$handle.tsx - Remix:
routes/products.$handle.tsx
Wrong examples:
- ❌
pages/products/blue-shirt.tsx(static file per product) - ❌
pages/products/red-shoes.tsx(doesn't scale)
Fetch product data in the dynamic route based on the handle/ID parameter from the URL.
Layout Structure
Desktop (two-column):
- Left: Product images (50-60% width)
- Right: Product info, variants, add to cart (40-50%)
- Below: Product details, reviews, related products (full-width)
Mobile (stacked):
- Images at top (full-width, swipeable)
- Product info below (title, price, rating)
- Variants and add to cart
- Accordion for product details
- Reviews section
- Related products
- Sticky "Add to Cart" bar at bottom
Sticky sidebar option (desktop):
- Product info column stays visible during scroll
- Add to cart always accessible
- Useful for long product descriptions
- Improves conversion
Price Display
Standard Price Display
Current price:
- Large, bold font (28-36px)
- Currency symbol included ($49.99)
- Primary color or black
Sale pricing:
- Original price with strikethrough:
$79.99$49.99 - Sale price in red or brand color
- "Save X%" badge nearby
- Example: Save 37%
Variant price changes:
- When no variant selected: Show "From $X" where X is the minimum variant price across all variants
- When variant selected: Update price dynamically to show the exact variant price
- No page reload required
- Show price change clearly (highlight briefly on change)
- Example: Product with variants priced at $29.99, $34.99, $39.99 → Show "From $29.99" initially
Medusa Pricing (CRITICAL)
Important difference from Stripe:
- Medusa stores prices as-is (e.g., 49.99)
- Display directly: If API returns 49.99, show $49.99
- DON'T divide by 100 (unlike Stripe which stores in cents)
- Example: Medusa 49.99 → Display $49.99 (NOT $0.4999)
Multi-currency (Medusa):
- Medusa supports multi-region pricing
- Display price in user's region currency
- Fetch pricing from selected region
- Show currency code (usd, eur, etc.)
Variant Selection (Critical)
This is a complex ecommerce-specific challenge. Variants affect price, stock, and images.
Variant Complexity
Key challenges:
- Multiple variant types (size, color, material)
- Variant availability varies (some sizes out of stock)
- Prices may differ by variant
- Images change by color variant
- Stock levels per variant
- Combinations may not exist (size M + color Red might not exist)
Fetch from backend:
// Get all variants for product
// Change this based on the backend integrated
const product = await fetch(`/products/${id}?fields=*variants`)
// Returns variants with: id, sku, options, calculated_price, inventory_quantity
Variant Selection Patterns
Use Button Group when:
- 2-8 options per variant type
- Size selection (XS, S, M, L, XL)
- Simple color options (5-6 colors)
- Users need to see all options at once
Benefits:
- Visible options (no click to reveal)
- Faster selection
- Clear visual feedback
- Better UX
Use Dropdown when:
- 10+ options per variant type
- Material/style options with long names
- Space-constrained layouts
- Mobile optimization needed
Benefits:
- Saves space
- Works better for many options
- Mobile-friendly
Use Visual Swatches when:
- Color or pattern variations
- Material with visual differences
- Visual is key to decision
- Fashion, home decor, customizable products
Implementation:
- Circular/square swatches (40-48px)
- Border on selected
- Show product image in that color when selected
- Color name on hover
- Gray out unavailable colors
Variant Selection Flow
Critical sequence:
- User selects first variant type (e.g., Color: Blue)
- Update available options for other variant types
- Show only size options available for Blue color
- Gray out/disable unavailable combinations
- Update price if variant price differs
- Update main product image to show selected variant
- Update stock availability
- Enable/disable "Add to Cart" based on availability
Example: Two variants (Color + Size)
// When color selected
// Change this based on the backend integrated
onColorSelect(color) {
// Find selected variant
const selectededVariant = product.variants.find((variant) => variant.options?.every(
(optionValue) => optionValue.id === selectedOptions[optionValue.option_id!]
))
// Check if size is selected and update price
if (selectededVariant) {
const variant = findVariant(color, selectedSize)
updatePrice(variant.price)
updateStock(variant.inventory_quantity)
}
}
Validation and Error Handling
Prevent adding without selection:
- Disable "Add to Cart" until all required variants selected
- Or: Show error message "Please select a size"
- Highlight missing selection (red border around options)
- Scroll to variant selection on error
Handle out of stock variants:
- Gray out unavailable options
- "Out of stock" text on hover
- Don't allow selection of out of stock variants
- Suggest alternative variants if available
Handle variant not found:
- When combination doesn't exist (Size M + Color Red)
- Disable second option when first selected
- Show only valid combinations
- Or: Show "This combination is not available"
Stock Availability
Display patterns:
In stock:
- Green indicator (✓ or dot)
- "In stock" or "Available"
- Quantity if low: "Only 3 left"
- Encourages urgency without being pushy
Out of stock:
- Red indicator (✗ or dot)
- "Out of stock" message
- Disable "Add to Cart" button (grayed out)
- Offer "Notify me when available"
- Email capture for restock notifications (if supported by backend)
Low stock warning:
- "Only X left in stock"
- Shows scarcity (increases urgency)
- Typically show when <= 5 items
- Orange/yellow color
Pre-order:
- "Pre-order now" status
- Expected availability date: "Ships on [Date]"
- Different button text: "Pre-order" instead of "Add to Cart"
- Charge now or later (specify)
Backend integration:
// Fetch stock for selected variant
const stock = selectedVariant.inventory_quantity
if (stock === 0) {
showOutOfStock()
} else if (stock <= 5) {
showLowStock(stock) // "Only 3 left"
} else {
showInStock()
}
Add to Cart Behavior
Button states:
- Default: Enabled (after variant selected)
- Hover: Slight color change or scale
- Loading: Spinner inside button (during API call)
- Success: Checkmark briefly, then revert
- Disabled: Grayed out (no variant or out of stock)
Click behavior (Critical):
- Show loading state (disable button, show spinner)
- Call API to add item to cart (backend)
- Optimistic UI: Update cart count immediately (before API response)
- Show success feedback (toast, checkmark, or cart popup)
- Update cart count in navbar header
- DON'T navigate away - stay on product page
- Handle errors: restore count if API fails
Success feedback options:
- Toast notification: "Added to cart" (top-right)
- Cart popup: Show mini cart with items (see cart-popup.md)
- Checkmark in button briefly, then revert
- All three combined (checkmark + toast or cart popup)
Error handling:
async function addToCart(variantId, quantity) {
try {
// Optimistic update
updateCartCountUI(+quantity)
// API call
// Change this based on the backend integrated
await fetch(`/store/carts/${cartId}/line-items`, {
method: 'POST',
body: JSON.stringify({ variant_id: variantId, quantity })
})
// Success feedback
showToast('Added to cart')
showCartPopup() // Optional
} catch (error) {
// Revert optimistic update
updateCartCountUI(-quantity)
// Show error
if (error.message === 'OUT_OF_STOCK') {
showError('Sorry, this item is now out of stock')
updateStockStatus('out_of_stock')
} else {
showError('Failed to add to cart. Please try again.')
}
}
}
Buy Now button (optional):
- Skip cart, go directly to checkout
- Useful for: high-value items, single-item stores, decisive customers
- Secondary button below "Add to Cart"
- Text: "Buy Now" or "Buy It Now"
- Add to cart + redirect to checkout in one action
Product Details Organization
Decision: Tabs vs Accordion
Use Tabs (desktop) when:
- 3-5 distinct sections
- Each section has substantial content
- Users may want to compare sections
- Desktop has screen space
- Examples: Description, Specifications, Shipping, Reviews
Use Accordion (mobile) always:
- Saves vertical space
- Users expand what they need
- Standard mobile pattern
- Collapses after reading
Hybrid approach (recommended):
- Tabs on desktop (horizontal navigation)
- Accordion on mobile (vertical expansion)
- Same content, different presentation
- Best of both worlds
Common Sections
Description:
- Product overview (2-4 paragraphs)
- Key features (bullet points)
- Use cases
- Materials and craftsmanship
Specifications:
- Technical details (table format)
- Dimensions, weight, materials
- Care instructions
- Compatibility information
Shipping & Returns:
- Shipping options and costs
- Delivery timeframes
- Return policy (30 days, 60 days)
- Return process
- Link to full policy page
Reviews:
- Embedded in tab/accordion
- Or: Separate section below
- Filter by rating, sort by date
- Review submission form
Related Products Strategy
Types of recommendations:
"You May Also Like" (Similar products):
- Same category, similar price point
- Algorithm: category match + price range
- Goal: Show alternatives if unsure about current product
"Frequently Bought Together" (Complementary):
- Products commonly purchased together
- Algorithm: order history analysis
- Goal: Increase average order value
- Example: Phone + Case + Screen Protector
- Show bundle discount if available
"Recently Viewed" (Browsing history):
- User's browsing history (session or logged-in)
- Helps users return to products they liked
- Goal: Reduce decision paralysis
"Customers Also Viewed":
- Products viewed by others who viewed this
- Algorithm: co-viewing patterns
- Goal: Discovery and alternatives
Display Pattern
Product slider:
- 4-6 products visible (desktop)
- 2-3 visible (mobile)
- Horizontal scrolling (swipe on mobile)
- Product cards: image, title, price, rating
- Optional: Quick "Add to Cart" on hover
Placement:
- Below product details and reviews
- Above footer
- Full-width section
- Clear heading for each type
Backend integration:
// Fetch recommendations
// Change this based on the backend integrated
const recommendations = await fetch(`/products/${id}/recommendations`)
// Returns: similar, bought_together, recently_viewed
Trust Signals and Conversion
Essential trust signals:
Near Add to Cart:
- Free shipping badge (if applicable)
- Free returns icon + text
- Secure checkout icon
- Money-back guarantee
- Warranty information (if applicable)
Below product title:
- Customer rating and review count (4.8 ★ 324 reviews)
- Link to reviews section
- "Best seller" or "Top rated" badge
Payment methods:
- Accepted payment icons (Visa, Mastercard, PayPal, Apple Pay)
- Small icons (40px)
- Below "Add to Cart" or in footer
- Shows payment options available
For new/unknown brands:
- Customer testimonials
- "Join 10,000+ happy customers"
- Security badges (if legitimate - don't fake)
- Social proof (Instagram photos, user content)
- Clear contact information
For high-value products:
- Detailed specifications
- Professional photography
- Video demonstrations
- Warranty details prominently displayed
- Customer service contact visible
Mobile Optimization
Critical mobile patterns:
Sticky "Add to Cart" bar:
- Fixed at bottom of screen
- Always accessible (no scrolling needed)
- Shows: Price + "Add to Cart" button
- Appears after scrolling past fold
- Higher conversion rates
Image gallery:
- Full-width swipeable carousel
- Pinch to zoom
- Dot indicators (1/5, 2/5)
- Tap to open full-screen view
Variant selection:
- Large touch targets (44-48px)
- Visual swatches easier than dropdowns
- Clear selected state
- Error messages visible
Accordion for details:
- Description, Specs, Shipping as accordion
- Starts collapsed (save space)
- User expands what they need
- Clear expand/collapse indicators
Reviews section:
- Expandable (start with 2-3 reviews)
- "Show more" button
- Filter by rating
- Star rating distribution chart
Checklist
Essential product detail page features:
- High-quality product images with zoom
- Price displayed correctly (Medusa: use value as-is, not divided)
- Price shows "From $X" when no variant selected (X = minimum variant price)
- Variant selection required before adding to cart
- Variant selection updates: price, stock, image
- Disable unavailable variant options (gray out)
- Stock availability indicator (in stock, low stock, out of stock)
- "Only X left" shown when stock is low (<=5)
- Add to Cart disabled until variant selected
- Optimistic UI update (cart count updates immediately)
- Success feedback (toast, cart popup, or checkmark)
- Stay on product page after adding (don't navigate away)
- Error handling (out of stock, API failure)
- Product description and specifications
- Customer reviews and ratings
- Related products recommendations (similar, bought together)
- Trust signals (free shipping, returns, secure checkout)
- Payment method icons displayed
- Breadcrumb navigation
- Mobile: Swipeable image gallery
- Mobile: Accordion for product details
- Mobile: Sticky Add to Cart bar (optional but effective)
- Tabs on desktop, accordion on mobile (hybrid)
- Fast loading (<2s, optimize images)
- Keyboard accessible (tab through options, enter to add)
- ARIA labels on variant selection (role="group", aria-label)