Initial commit
This commit is contained in:
@@ -0,0 +1,527 @@
|
||||
# Product Detail Page Layout
|
||||
|
||||
## Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Layout Structure](#layout-structure)
|
||||
- [Price Display and Medusa Integration](#price-display-and-medusa-integration)
|
||||
- [Variant Selection (Critical)](#variant-selection-critical)
|
||||
- [Stock Availability](#stock-availability)
|
||||
- [Add to Cart Behavior](#add-to-cart-behavior)
|
||||
- [Product Details Organization](#product-details-organization)
|
||||
- [Related Products Strategy](#related-products-strategy)
|
||||
- [Trust Signals and Conversion](#trust-signals-and-conversion)
|
||||
- [Mobile Optimization](#mobile-optimization)
|
||||
- [Checklist](#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:**
|
||||
```typescript
|
||||
// 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:**
|
||||
1. User selects first variant type (e.g., Color: Blue)
|
||||
2. **Update available options** for other variant types
|
||||
3. Show only size options available for Blue color
|
||||
4. Gray out/disable unavailable combinations
|
||||
5. Update price if variant price differs
|
||||
6. Update main product image to show selected variant
|
||||
7. Update stock availability
|
||||
8. Enable/disable "Add to Cart" based on availability
|
||||
|
||||
**Example: Two variants (Color + Size)**
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
// 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):**
|
||||
1. Show loading state (disable button, show spinner)
|
||||
2. Call API to add item to cart (backend)
|
||||
3. **Optimistic UI**: Update cart count immediately (before API response)
|
||||
4. Show success feedback (toast, checkmark, or cart popup)
|
||||
5. Update cart count in navbar header
|
||||
6. **DON'T navigate away** - stay on product page
|
||||
7. 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:**
|
||||
```typescript
|
||||
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:**
|
||||
```typescript
|
||||
// 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)
|
||||
Reference in New Issue
Block a user