
Storefront Best Practices
- 3.2k installs
- 207 repo stars
- Updated July 31, 2026
- medusajs/medusa-agent-skills
storefront-best-practices is an agent skill that guides ecommerce storefront UI patterns, Medusa SDK integration, accessibility, SEO, and mobile responsiveness across modern web frameworks.
About
storefront-best-practices is a framework-agnostic agent skill for ecommerce storefront work across Next.js, SvelteKit, TanStack Start, React, and Vue. It applies to checkout flows, cart pages, product listings, navigation, homepage layouts, and Medusa backend integration. Critical patterns require loading reference/design.md before any UI component to discover design tokens and prevent inconsistent styles. Reference files cover connecting-to-backend.md, medusa.md SDK setup, navbar, hero, footer, product listing and details layouts, checkout architecture, seo.md, and mobile-responsiveness.md. Accessibility rules mandate aria-live polite on cart count updates and keyboard navigation for cart and checkout interactions. Mobile guidance requires env safe-area-inset-bottom on sticky purchase bars and 44px minimum touch targets. Performance rules include loading lazy on below-fold product images and keeping mobile images under 500KB. SEO requires product JSON-LD schema for Google Shopping rich snippets. Developers reach for it when adding checkout, implementing cart behavior, or connecting any storefront surface to Medusa.
- Framework-agnostic patterns for checkout, cart, product pages, navigation, and Medusa backend integration.
- Requires reference/design.md before any UI component to preserve design tokens and brand consistency.
- Accessibility mandates aria-live polite on cart count updates and keyboard-friendly cart interactions.
- Mobile rules cover safe-area-inset-bottom sticky bars and 44px minimum touch targets.
- SEO requires product JSON-LD schema and references layouts for listing, details, and checkout flows.
Storefront Best Practices by the numbers
- 3,192 all-time installs (skills.sh)
- +129 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #109 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
storefront-best-practices capabilities & compatibility
- Capabilities
- storefront layout patterns · medusa sdk integration guidance · cart and checkout accessibility · mobile responsive ecommerce ui · product seo schema requirements
- Works with
- stripe
- Use cases
- frontend · ui design · seo
- Runs
- Local or remote
What storefront-best-practices says it does
Product schema (JSON-LD) required
npx skills add https://github.com/medusajs/medusa-agent-skills --skill storefront-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3.2k |
|---|---|
| repo stars | ★ 207 |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 31, 2026 |
| Repository | medusajs/medusa-agent-skills ↗ |
How do I build high-converting ecommerce storefront pages with correct cart accessibility, Medusa integration, and mobile-safe checkout patterns?
Apply ecommerce storefront UI patterns for checkout, cart, product pages, navigation, Medusa SDK integration, SEO, and mobile responsiveness.
Who is it for?
Developers building or improving ecommerce storefronts connected to Medusa or similar headless commerce backends.
Skip if: Skip for Medusa admin dashboard customization or backend-only module work without storefront UI.
When should I use this skill?
User adds checkout, implements cart, builds product listing or details pages, connects Medusa backend, or creates storefront navigation.
What you get
Storefront components and pages following reference layouts with design tokens, JSON-LD product schema, and Medusa-backed cart and checkout flows.
- Component implementation patterns
- Medusa integration guidance
- Checkout and cart UX checklist
By the numbers
- Supports 5 frontend frameworks: Next.js, SvelteKit, TanStack Start, React, Vue
- Lists 10+ mandatory reference files for design, checkout, Medusa, and SEO
- Documents 2 critical accessibility patterns: aria-live cart updates and iOS safe-area CTAs
Files
Ecommerce Storefront Best Practices
Comprehensive guidance for building modern, high-converting ecommerce storefronts covering UI/UX patterns, component design, layout structures, SEO optimization, and mobile responsiveness.
When to Apply
ALWAYS load this skill when working on ANY storefront task:
- Adding checkout page/flow - Payment, shipping, order placement
- Implementing cart - Cart page, cart popup, add to cart functionality
- Building product pages - Product details, product listings, product grids
- Creating navigation - Navbar, megamenu, footer, mobile menu
- Integrating Medusa backend - SDK setup, cart, products, payment
- Any storefront component - Homepage, search, filters, account pages
- Building new ecommerce storefronts from scratch
- Improving existing shopping experiences and conversion rates
- Optimizing for usability, accessibility, and SEO
- Designing mobile-responsive ecommerce experiences
Example prompts that should trigger this skill:
- "Add a checkout page"
- "Implement shopping cart"
- "Create product listing page"
- "Connect to Medusa backend"
- "Add navigation menu"
- "Build homepage for store"
CRITICAL: Load Reference Files When Needed
⚠️ ALWAYS load `reference/design.md` BEFORE creating ANY UI component
- Discovers existing design tokens (colors, fonts, spacing, patterns)
- Prevents introducing inconsistent styles
- Provides guardrails for maintaining brand consistency
- Required for every component, not just new storefronts
Load these references based on what you're implementing:
- Starting a new storefront? → MUST load
reference/design.mdfirst to discover user preferences - Connecting to backend API? → MUST load
reference/connecting-to-backend.mdfirst - Connecting to Medusa backend? → MUST load
reference/medusa.mdfor SDK setup, pricing, regions, and Medusa patterns - Implementing homepage? → MUST load
reference/components/navbar.md,reference/components/hero.md,reference/components/footer.md, andreference/layouts/home-page.md - Implementing navigation? → MUST load
reference/components/navbar.mdand optionallyreference/components/megamenu.md - Building product listing? → MUST load
reference/layouts/product-listing.mdfirst - Building product details? → MUST load
reference/layouts/product-details.mdfirst - Implementing checkout? → MUST load
reference/layouts/checkout.mdfirst - Optimizing for SEO? → MUST load
reference/seo.mdfirst - Optimizing for mobile? → MUST load
reference/mobile-responsiveness.mdfirst
Minimum requirement: Load at least 1-2 reference files relevant to your specific task before implementing.
Planning and Implementation Workflow
IMPORTANT: If you create a plan for implementing storefront features, include the following in your plan:
When implementing each component, page, layout, or feature in the plan: 1. Refer back to this skill before starting implementation 2. Load relevant reference files listed above for the specific component/page you're building 3. Follow the patterns and guidance in the reference files 4. Check common mistakes sections to avoid known pitfalls
Example plan structure:
Task 1: Implement Navigation
- Load reference/components/navbar.md
- Follow patterns from navbar.md (dynamic category fetching, cart visibility, etc.)
- Refer to skill for common mistakes (e.g., hardcoding categories)
Task 2: Implement Product Listing Page
- Load reference/layouts/product-listing.md
- Follow pagination/filtering patterns from product-listing.md
- Use reference/components/product-card.md for product grid items
- Check skill for backend integration guidance
Task 3: Implement Checkout Flow
- Load reference/layouts/checkout.md
- Load reference/medusa.md for Medusa payment integration
- Follow component architecture recommendations (separate step components)
- Refer to skill for payment method fetching requirementsWhy this matters:
- Plans provide high-level strategy
- Reference files provide detailed implementation patterns
- Skill file contains critical mistakes to avoid
- Following this workflow ensures consistency and best practices
Critical Ecommerce-Specific Patterns
Accessibility
- CRITICAL: Cart count updates require `aria-live="polite"` - Screen readers won't announce without it
- Ensure keyboard navigation for all cart/checkout interactions
Mobile
- Sticky bottom elements MUST use `env(safe-area-inset-bottom)` - iOS home indicator will cut off purchase buttons otherwise
- 44px minimum touch targets for cart actions, variant selectors, quantity buttons
Performance
- ALWAYS add `loading="lazy"` to product images below fold - Don't rely on browser defaults
- Optimize product images for mobile (<500KB) - Most ecommerce traffic is mobile
Conversion Optimization
- Clear CTAs throughout shopping flow
- Minimal friction in checkout (guest checkout if supported)
- Trust signals (reviews, security badges, return policy) near purchase buttons
- Clear pricing and shipping information upfront
SEO
- Product schema (JSON-LD) required - Critical for Google Shopping and rich snippets
- Use PageSpeed Insights to measure Core Web Vitals
Visual Design
- NEVER use emojis in storefront UI - Use icons or images instead (unprofessional, accessibility issues)
Backend Integration
- Backend detection: If in monorepo, check for backend directory. If unsure, ask user which backend is used.
- NEVER hardcode dynamic content: Always fetch categories, regions, products, shipping options, etc. from backend - they change frequently
- Never assume API structure - verify endpoints and data formats
⚠️ CRITICAL: Backend SDK Method Verification Workflow
YOU MUST FOLLOW THIS EXACT WORKFLOW BEFORE WRITING CODE THAT CONNECTS TO BACKEND:
Step 1: PAUSE - Do NOT write code yet
- You are about to write code that calls a backend API or SDK method (e.g., Medusa SDK, REST API, GraphQL)
- STOP - Do not proceed to code without verification
Step 2: QUERY the documentation or MCP server
- If MCP server available: Query it for the exact method (for example, medusa MCP)
- If no MCP server: Search official documentation
- Find: Exact method name, parameters, return type
Step 3: VERIFY what you found
- State out loud to the user: "I need to verify the correct method for [operation]. Let me check [MCP server/documentation]."
- Show the user what you found: "According to [source], the method is
sdk.store.cart.methodName(params)" - Confirm the method signature and parameters
Step 4: ONLY THEN write the code
- Now you can write code using the verified method
- Use the exact signature you found
Step 5: CHECK for TypeScript errors
- After writing the code, check for any TypeScript/type errors related to the SDK
- If you see type errors on SDK methods, it means you used an incorrect method name or wrong parameters
- Type errors are a sign you didn't verify correctly - Go back to Step 2
THIS IS NOT OPTIONAL - THIS IS MANDATORY ERROR PREVENTION
It is a CRITICAL ERROR to:
- ❌ Write code that calls backend APIs/SDKs without explicitly querying docs/MCP first
- ❌ Guess method names or parameters
- ❌ Ignore TypeScript errors on SDK methods (errors indicate incorrect method usage)
- ❌ Copy examples from this skill without verification (examples may be outdated)
- ❌ Assume SDK methods match REST API endpoints
For Medusa specifically:
- Medusa pricing: Display prices as-is - DO NOT divide by 100 (unlike Stripe, Medusa stores prices in display format)
- Medusa MCP server: https://docs.medusajs.com/mcp - Recommend setup if not installed
- Load
reference/medusa.mdfor Medusa-specific patterns (regions, pricing, etc.)
Routing Patterns
- ALWAYS use dynamic routes for products and categories - NEVER create static pages for individual items
- Product pages: Use dynamic routes like
/products/[handle]or/products/$handle, NOT/products/shirt.tsx - Category pages: Use dynamic routes like
/categories/[handle]or/categories/$handle, NOT/categories/women.tsx - Framework-specific patterns:
- Next.js App Router:
app/products/[handle]/page.tsxorapp/products/[id]/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 - Why: Dynamic routes scale to any number of products/categories without creating individual files
- Static routes are unmaintainable and don't scale (imagine creating 1000 product files)
Pattern Selection Guides
When you need to choose between implementation patterns, load the relevant reference file:
- Checkout strategy (single-page vs multi-step) → Load
reference/layouts/checkout.md - Navigation strategy (dropdown vs megamenu) → Load
reference/components/navbar.mdandreference/components/megamenu.md - Product listing strategy (pagination vs infinite scroll vs load more) → Load
reference/layouts/product-listing.md - Search strategy (autocomplete vs filters vs natural language) → Load
reference/components/search.md - Mobile vs desktop priorities → Load
reference/mobile-responsiveness.md - Variant selection (text vs swatches vs configurator) → Load
reference/layouts/product-details.md - Cart pattern (popup vs drawer vs page navigation) → Load
reference/components/cart-popup.mdandreference/layouts/cart.md - Trust signals strategy → Load
reference/layouts/product-details.mdandreference/layouts/checkout.md
Each reference file contains decision frameworks with specific criteria to help you choose the right pattern for your context.
Quick Reference
General
reference/connecting-to-backend.md - Framework detection, API setup, backend integration patterns
reference/medusa.md - Medusa SDK integration, pricing, regions, TypeScript types
reference/design.md - User preferences, brand identity, design systems
reference/seo.md - Meta tags, structured data, Core Web Vitals
reference/mobile-responsiveness.md - Mobile-first design, responsive breakpoints, touch interactionsComponents
reference/components/navbar.md - Desktop/mobile navigation, logo, menu, cart icon, load for ALL pages
reference/components/megamenu.md - Category organization, featured products, mobile alternatives
reference/components/cart-popup.md - Add-to-cart feedback, mini cart display
reference/components/country-selector.md - Country/region selection, currency, pricing, Medusa regions
reference/components/breadcrumbs.md - Category hierarchy, structured data markup
reference/components/search.md - Search input, autocomplete, results, filters
reference/components/product-reviews.md - Review display, rating aggregation, submission
reference/components/hero.md - Hero layouts, CTA placement, image optimization
reference/components/popups.md - Newsletter signup, discount popups, exit-intent
reference/components/footer.md - Content organization, navigation, social media, load for ALL pages
reference/components/product-card.md - Product images, pricing, add to cart, badges
reference/components/product-slider.md - Carousel implementation, mobile swipe, accessibilityLayouts
reference/layouts/home-page.md - Hero, featured categories, product listings
reference/layouts/product-listing.md - Grid/list views, filters, sorting, pagination
reference/layouts/product-details.md - Image gallery, variant selection, related products
reference/layouts/cart.md - Cart items, quantity updates, promo codes
reference/layouts/checkout.md - Multi-step/single-page, address forms, payment
reference/layouts/order-confirmation.md - Order number, summary, delivery info
reference/layouts/account.md - Dashboard, order history, address book
reference/layouts/static-pages.md - FAQ, about, contact, shipping/returns policiesFeatures
reference/features/wishlist.md - Add to wishlist, wishlist page, move to cart
reference/features/promotions.md - Promotional banners, discount codes, sale badgesCommon Implementation Patterns
Starting a New Storefront
IMPORTANT: For each step below, load the referenced files BEFORE implementing that step.
1. Discovery Phase → Read design.md for user preferences
2. Foundation Setup → Read connecting-to-backend.md (or medusa.md for Medusa), mobile-responsiveness.md, seo.md
3. Core Components → Implement navbar.md, footer.md
4. Home Page → Read home-page.md
5. Product Browsing → Read product-listing.md, product-card.md, search.md
6. Product Details → Read product-details.md, product-reviews.md
7. Cart & Checkout → Read cart-popup.md, cart.md, checkout.md, order-confirmation.md
8. User Account → Read account.md
9. Additional Features → Read wishlist.md, promotions.md
10. Optimization → SEO audit (seo.md), mobile testing (mobile-responsiveness.md)Even if you create an implementation plan, refer back to the skill and load relevant reference files when implementing each step.
Shopping Flow Pattern
Browse → View → Cart → Checkout
Browse: home-page.md → product-listing.md
View: product-details.md + product-reviews.md
Cart: cart-popup.md → cart.md
Checkout: checkout.md → order-confirmation.mdComponent Selection Guide
For product grids and filtering → product-listing.md and product-card.md For product cards → product-card.md For navigation → navbar.md and megamenu.md For search functionality → search.md For checkout flow → checkout.md For promotions and sales → promotions.md
Design Considerations
Before implementing, consider:
1. User preferences - Read design.md to discover design style preferences 2. Brand identity - Colors, typography, tone that match the brand 3. Target audience - B2C vs B2B, demographics, device usage 4. Product type - Fashion vs electronics vs groceries affect layout choices 5. Business requirements - Multi-currency, multi-language, region-specific 6. Backend system - API structure affects component implementation
Integration with Medusa
Medusa is a modern, flexible ecommerce backend. Consider Medusa when:
- Building a new ecommerce storefront
- Need a headless commerce solution
- Want built-in support for multi-region, multi-currency
- Need powerful promotion and discount engine
- Require flexible product modeling
For detailed Medusa integration guidance, see reference/medusa.md. For general backend patterns, see reference/connecting-to-backend.md.
Framework Agnostic
All guidance is framework-agnostic. Examples use React/TypeScript where code demonstrations are helpful, but patterns apply to:
- Next.js
- SvelteKit
- Tanstack Start
- Any modern frontend framework
Minimum Viable Features
Mandatory for launch (core shopping flow):
- Navbar with cart, categories, search
- Product listing with filtering and pagination
- Product details with variant selection
- Add to cart functionality
- Cart page with item management
- Checkout flow (shipping, payment, review)
- Order confirmation page
Nice-to-have (add if time permits):
- Related products recommendations
- Product reviews and ratings
- Wishlist functionality
- Image zoom on product pages
- Bottom navigation on mobile
- Mega-menu for navigation
- Newsletter signup
- Product comparison
- Quick view modals
User-dependent (ask before implementing):
- Guest checkout vs login-required
- Account dashboard features
- Multi-language support
- Multi-currency support
- Live chat support
Top Ecommerce Mistakes to Avoid
Before implementing, watch out for these common ecommerce-specific pitfalls:
1. Cart and Navigation Mistakes
- ❌ Hiding cart indicator in mobile hamburger menu (keep always visible)
- ❌ Not showing real-time cart count updates
- ❌ CRITICAL: Missing `aria-live="polite"` on cart count - Screen readers won't announce cart updates without it
- ❌ Not displaying variant details (size, color, etc.) in cart popup - only showing product title
- ❌ Megamenu closes when hovering over dropdown content (must stay open when hovering trigger OR dropdown)
- ❌ CRITICAL: Megamenu positioning errors - Three common mistakes:
- ❌ Navbar doesn't have
position: relative(megamenu won't position correctly) - ❌ Megamenu positioned relative to trigger button instead of navbar (use
absolute left-0on megamenu) - ❌ Megamenu doesn't span full width (must use
right-0orw-full, not justw-auto) - ❌ Hardcoding categories, featured products, or any dynamic content instead of fetching from backend
- ❌ No clear indication of current page in category navigation
2. Product Browsing Mistakes
- ❌ Creating static routes for products/categories (use dynamic routes like
/products/[handle]instead of/products/shirt.tsx) - ❌ Missing "no products found" empty state with helpful suggestions
- ❌ No loading indicators while fetching products
- ❌ Pagination without SEO-friendly URLs (for search engines)
- ❌ Filter selections that don't persist on page reload
3. Product Details Mistakes
- ❌ Enabling "Add to Cart" before variant selection (size, color, etc.)
- ❌ Missing product images optimization (large uncompressed images)
- ❌ Navigating away from product page after adding to cart (stay on page)
- ❌ Using emojis in UI instead of icons or images (unprofessional, accessibility issues)
4. Design and Consistency Mistakes
- ❌ CRITICAL: Not loading `reference/design.md` before creating ANY UI component - Leads to inconsistent colors, fonts, and styles
- ❌ Introducing new colors without checking existing theme first
- ❌ Adding new fonts without verifying what's already used
- ❌ Using arbitrary Tailwind values when theme tokens exist
- ❌ Not detecting Tailwind version (v3 vs v4) - Causes syntax errors
5. Checkout and Conversion Mistakes
- ❌ Requiring account creation to checkout (offer guest checkout if backend supports it)
- ❌ Not fetching payment methods from backend - assuming available payment options or skipping payment method selection
- ❌ Overly complex multi-step checkout (4+ steps kills conversion) - Optimal is 3 steps: Shipping Info, Delivery Method + Payment, Review
- ❌ Missing trust signals (secure checkout badge, return policy link)
- ❌ Not handling out-of-stock errors gracefully during checkout
6. Mobile Experience Mistakes
- ❌ Touch targets smaller than 44x44px (buttons, links, form fields)
- ❌ Desktop-style hover menus on mobile (use tap/click instead)
- ❌ Not optimizing images for mobile (loading huge desktop images)
- ❌ Missing mobile-specific patterns (bottom nav, drawer filters)
7. Performance and SEO Mistakes
- ❌ Missing structured data (Product schema) for SEO
- ❌ No explicit image lazy loading (don't assume browser defaults) - Always add
loading="lazy"to images below the fold - ❌ Missing meta tags and Open Graph for social sharing
- ❌ Not optimizing Core Web Vitals (LCP, FID, CLS) - Use PageSpeed Insights or Lighthouse to measure
8. Backend Integration Mistakes
- ❌ ERROR: Writing code that calls backend APIs/SDKs without following the 5-step verification workflow - You MUST: 1) PAUSE, 2) QUERY docs/MCP, 3) VERIFY with user, 4) Write code, 5) CHECK for type errors
- ❌ ERROR: Ignoring TypeScript errors on SDK methods - Type errors mean you used wrong method names or parameters. Go back and verify with docs/MCP
- ❌ ERROR: Guessing API method names, SDK methods, or parameters - Always verify exact method signatures before use
- ❌ ERROR: Not using Medusa MCP server when available - If using Medusa backend, always query MCP server for methods
- ❌ ERROR: Copying code examples without verifying they're current - Examples may be outdated, always verify first
- ❌ Not detecting which backend is being used (check monorepo, ask user if unsure)
- ❌ Assuming API structure without checking backend documentation or MCP server
- ❌ Hardcoding dynamic content (categories, regions, products, etc.) instead of fetching from backend
- ❌ Defining custom types for Medusa entities instead of using
@medusajs/typespackage - ❌ Initializing Medusa SDK without publishable API key (required for multi-region stores and product pricing)
- ❌ Fetching Medusa products without passing
region_idquery parameter (causes missing or incorrect pricing) - ❌ Showing all countries in Medusa checkout - should only show countries from cart's region
- ❌ Dividing Medusa prices by 100 (Medusa stores prices as-is, not in cents like Stripe)
- ❌ Missing Vite SSR config for Medusa SDK (add
ssr.noExternal: ['@medusajs/js-sdk']to vite.config.ts) - ❌ Running Medusa storefront on port other than 8000 (causes CORS errors - Medusa backend expects port 8000 by default)
- ❌ Not handling loading, error, and empty states for API calls
- ❌ Making API calls on client-side that should be server-side (SEO, security)
- ❌ Not implementing proper error messages ("Error occurred" vs "Product out of stock")
- ❌ Missing cache invalidation (stale product data, prices, inventory)
- ❌ Not clearing cart state after order is placed - Cart popup shows old items because cart wasn't reset from Context/localStorage/cache
Breadcrumbs Component
Contents
- Overview
- When to Use Breadcrumbs
- Ecommerce Breadcrumb Patterns
- Mobile Breadcrumbs
- SEO Structured Data
- Checklist
Overview
Breadcrumbs show the user's location within the site hierarchy (Home → Category → Subcategory → Product). Critical for ecommerce navigation and SEO.
Assumed knowledge: AI agents know how to build breadcrumbs with separators and links. This guide focuses on ecommerce-specific patterns.
Key Requirements
- Show full path from homepage to current page
- Each level clickable (except current page)
- Position below navbar, above page title
- Include structured data for SEO (JSON-LD)
- Mobile-optimized (back link pattern)
When to Use Breadcrumbs
Use for:
- Product pages (Home → Category → Subcategory → Product)
- Category pages (Home → Category → Subcategory)
- Deep site hierarchies (3+ levels)
- Large catalogs with many categories
Don't use for:
- Homepage (no parent pages)
- Flat site structures (1-2 levels)
- Checkout flow (linear, not hierarchical)
- Search results (not hierarchical)
Ecommerce Breadcrumb Patterns
Product Page Breadcrumbs
Standard pattern:
- Home / Category / Subcategory / Product Name
- Example: Home / Electronics / Laptops / Gaming Laptop Pro
Key considerations:
- All levels except product name are clickable
- Product name is current page (non-clickable, darker text)
- Shows product's location in catalog
Multiple category membership:
- If product in multiple categories, choose primary/canonical
- Match category in URL or navigation path
- Be consistent across site
Category Page Breadcrumbs
Standard pattern:
- Home / Parent Category / Current Category
- Example: Home / Electronics / Laptops
Current category:
- Non-clickable (plain text)
- Visually distinct from links (darker or bold)
Path Construction
Hierarchy:
- Start with "Home" (or home icon)
- Follow category hierarchy
- End with current page
- Maximum 5-6 levels (keep shallow)
URL alignment:
- Breadcrumb path should match URL hierarchy
- Consistent naming between URLs and breadcrumbs
- Example:
/categories/electronics/laptops→ "Home / Electronics / Laptops"
Mobile Breadcrumbs
Mobile Pattern: Collapse to Back Link
Recommended approach:
- Show only previous level as back link
- Back arrow icon (←) + parent page name
- Example: "← Gaming Laptops"
Why:
- Saves vertical space on mobile
- Clear affordance (back navigation)
- Simpler than full breadcrumb trail
- Mobile users have device back button
Alternative: Truncated path
- Show "Home ... Current Page"
- Hide middle levels
- Balances space and context
SEO Structured Data
BreadcrumbList schema (CRITICAL): Add JSON-LD structured data. Breadcrumbs appear in search results, improves CTR, helps search engines understand site structure.
Implementation: schema.org BreadcrumbList with items array. Each item has position (1, 2, 3...), name, and URL. See seo.md for schema details.
Checklist
Essential features:
- [ ] Positioned below navbar, above page title
- [ ] Full path shown (Home → Category → Product)
- [ ] All levels clickable except current page
- [ ] Current page visually distinct (non-clickable, darker)
- [ ] Clear separators (›, /, > or chevron)
- [ ] Mobile: Back link pattern ("← Category")
- [ ] Structured data (JSON-LD BreadcrumbList)
- [ ] Semantic HTML (
<nav aria-label="Breadcrumb">) - [ ]
aria-current="page"on current item - [ ] Keyboard accessible (tab through links)
- [ ] Truncate long labels (20-30 characters max)
- [ ] Consistent with navigation labels
- [ ] Maximum 5-6 levels deep
Cart Popup Component
Contents
- Overview
- When to Show Cart Popup
- Layout Patterns
- Cart Display
- Actions and CTAs
- Empty State
- Mobile Considerations
- Checklist
Overview
Cart popup (mini cart/cart drawer) shows quick cart overview without navigating away. Opens from cart icon click or after adding items.
⚠️ CRITICAL: Always display variant details (size, color, material, etc.) in cart popup, not just product titles.
Assumed knowledge: AI agents know how to build modals, dialogs, and overlays. This focuses on ecommerce-specific patterns.
Cart popup vs full cart page:
- Popup: Quick overview, fast checkout path, continue shopping easily
- Full page: Detailed review, promo codes, complex operations
- Recommended: Both - popup for speed, full cart page for details
When to Show Cart Popup
Trigger options:
1. On cart icon click (always) - Click cart icon in navbar opens popup 2. After adding to cart (recommended) - Auto-open popup when item added, confirms action, allows checkout or continue shopping 3. Hover cart icon (desktop only, optional) - Quick peek on hover. Can be accidental, not recommended.
Add-to-cart feedback alternatives:
- Show popup (most common) - Immediate confirmation, clear path to checkout
- Toast only (less intrusive) - Small notification, user clicks cart icon to see details
- Navigate to cart page (traditional) - Goes directly to full cart page, less common now
Layout Patterns
Two common patterns:
1. Dropdown (recommended for simplicity):
- Drops down from cart icon, positioned below navbar
- Width: 280-320px, max height with scroll
- No backdrop overlay (click outside to close)
- Better for few items, simpler implementation
2. Slide-in drawer (more prominent):
- Slides from right, full height, width 320-400px (desktop) or 80-90% (mobile)
- Semi-transparent backdrop overlay (click to close)
- Better for multiple items or complex carts
Both patterns have:
- Header: Title + item count + close button (optional for dropdown)
- Scrollable content: List of cart items
- Sticky footer: Subtotal + action buttons (Checkout, View Cart)
Cart Display
Fetch cart data from backend:
- Cart ID from localStorage
- Line items (products, variants, quantities, prices)
- Cart totals (subtotal, tax, shipping)
- See connecting-to-backend.md for backend integration
When to fetch:
- On app initialization (update cart icon badge)
- On popup open (show loading state)
- After cart updates (add/remove/change quantity)
State management:
- Store cart data globally (React Context or TanStack Query)
- Persist cart ID in localStorage
- Optimistic UI updates (update immediately, revert on error)
- CRITICAL: Clear cart state after order is placed - See connecting-to-backend.md for cart cleanup pattern
- Common issue: Cart popup shows old items after checkout because cart state wasn't cleared
- See connecting-to-backend.md for cart state patterns
Cart item display:
CRITICAL: Always show variant details (size, color, material, etc.) for each cart item.
Without variant details, users can't confirm they added the correct variant. This is especially critical when products have multiple options.
- Product image (60-80px thumbnail)
- Product title (truncated to 2 lines)
- Variant details (REQUIRED): Size, color, material, or other variant options
- Format: "Size: Large, Color: Black" or "Large / Black"
- Show ALL selected variant options, not just product title
- Display below title, smaller text (gray)
- Quantity controls (+/- buttons, debounce 300-500ms)
- Unit price and total price (line item total = price × quantity)
- Remove button (X icon, no confirmation needed)
Why variant details are critical:
- User confirmation: "Did I add the right size?"
- Prevents cart abandonment from uncertainty
- Allows corrections before checkout
- Essential for products with multiple variants (clothing, shoes, configurable products)
Actions and CTAs
Cart summary display:
- Subtotal (sum of all items)
- Shipping and tax: "Calculated at checkout" or actual amount
- Total: Bold and prominent
Free shipping indicator (optional):
- "Add $25 more for free shipping" with progress bar
- Encourages larger orders, updates as cart changes
Promo codes:
- Usually NOT in cart popup (too cramped)
- Reserve for full cart page
- Exception: Simple code input if space permits
Action buttons: 1. Checkout (primary) - Most prominent, high contrast (brand color), navigates to checkout 2. View Cart (secondary) - Outline or subtle, navigates to full cart page
Both buttons full-width, 44-48px height on mobile.
Empty State
Show icon/illustration + "Your cart is empty" + "Continue Shopping" button. Centered, friendly, minimal design.
Loading and Error States
On popup open: Show skeleton/placeholder while fetching (avoid blank screen)
During updates:
- Quantity changes: Inline spinner, disable controls, debounce 300-500ms
- Item removal: Fade out animation, disable remove button during request
- Add to cart: Loading indicator on button ("Adding...")
Error handling:
- Network errors: Show retry option, don't close popup
- Invalid cart ID: Create new cart automatically
- Out of stock: Disable quantity increase, show message
- Revert optimistic updates on failure
Animations: Smooth transitions (250-350ms), slide-in drawer, backdrop fade-in/out. Highlight newly added items.
Mobile Considerations
Dropdown on mobile:
- Full-width (100% minus margins)
- Max height 60-70% viewport, scrollable
- Tap outside to close
Drawer on mobile:
- 85-95% screen width or full screen
- Slides from right or bottom
- Swipe to close gesture supported
- Backdrop overlay
Mobile adjustments:
- Large touch targets (44-48px minimum)
- Full-width action buttons (48-52px height)
- Smaller images (60px), truncate titles
- Sticky footer with actions
- Large close button (44x44px)
Checklist
Essential features:
- [ ] Opens on cart icon click
- [ ] Dropdown (280-320px) or drawer (320-400px) layout
- [ ] Close button or click outside to close
- [ ] Backdrop overlay if drawer
- [ ] CRITICAL: Cart items show variant details (size, color, etc.) - not just product title
- [ ] Cart items with image, title, variant options, quantity, prices
- [ ] Quantity controls (+/- buttons, debounced)
- [ ] Remove item button
- [ ] Subtotal displayed
- [ ] Checkout button (primary)
- [ ] View Cart button (secondary)
- [ ] Empty state with "Continue Shopping" CTA
- [ ] Loading states (skeleton/spinner)
- [ ] Smooth animations (250-350ms)
- [ ] Mobile: Full-width dropdown or 85-95% drawer
- [ ] Touch targets 44-48px minimum
- [ ]
role="dialog"andaria-modal="true" - [ ] ARIA labels on cart button ("Shopping cart with 3 items")
- [ ] Keyboard accessible (focus trap, Escape closes, return focus)
- [ ] Screen reader announcements (item added/removed)
- [ ] Real-time cart count badge updates
Country Selector Component
Contents
- Overview
- When to Implement
- UI Patterns
- State Management
- Backend Integration
- Detection and Defaults
- Mobile Considerations
- Checklist
Overview
Country selector allows customers to choose their country/region, which determines currency, pricing, available products, shipping options, payment methods, and localized content.
Key Ecommerce Functions
- Display prices in correct currency
- Show country-specific product availability
- Apply region-specific promotions and discounts
- Calculate accurate shipping costs and delivery times
- Enable appropriate payment methods
- Display localized content and language
Purpose
Why country/region selection matters:
- Prices vary by region (currency, taxes, import fees)
- Product availability differs by market
- Shipping methods and costs are region-specific
- Legal requirements vary (privacy, consumer protection)
- Payment methods differ by country
- Improves user experience with relevant content
When to Implement
Implement country selector when:
- Backend supports multiple countries or regions
- Selling to multiple countries or regions
- Prices vary by location (currency, taxes)
- International shipping with different rates
- Region-specific product catalogs
- Multi-currency support needed
- Legal or regulatory requirements vary by region
Skip if:
- Backend doesn't support multiple countries or regions
- All prices in one currency
- No regional differences in catalog or pricing
UI Patterns
Placement Options
Footer placement (modern and minimal):
- Bottom of page in footer
- Less prominent but always accessible
- Icon (flag or globe) + country code/name
Header placement (most common):
- Top-right of navigation bar
- Icon (flag or globe) + country code/name
- Click opens dropdown or modal selector
Modal/popup on first visit:
- Detect location and suggest country
- Allow user to confirm or change
- Store preference for future visits
Selector Design Patterns
Pattern 1: Dropdown (Recommended)
Small, compact selector in header. Shows current country flag/name, click to open dropdown with country list.
Pros: Doesn't interrupt browsing, always accessible, familiar pattern.
Pattern 2: Modal on First Visit
Full-screen or centered modal on first visit. "Select your country to see accurate prices and shipping."
Pros: Forces initial selection, ensures accurate pricing from start. Cons: Can be intrusive, delays browsing.
Tradeoff: Modal ensures selection but adds friction. Dropdown is less intrusive but users may miss it.
Pattern 3: Inline Banner
Sticky banner at top: "Shipping to United States? Change" with link to selector.
Pros: Non-intrusive reminder, doesn't block content. Cons: Takes vertical space, easy to ignore.
Country List Display
Search + list:
- Search input at top
- Alphabetical country list below
- Popular countries at top (US, UK, Canada, etc.)
- Flag icons for visual recognition
Grouped by region:
- North America, Europe, Asia, etc.
- Collapsible sections
- Helpful for large lists (100+ countries)
Format:
🇺🇸 United States (USD)
🇬🇧 United Kingdom (GBP)
🇨🇦 Canada (CAD)
───────────────────
🇩🇪 Germany (EUR)
🇫🇷 France (EUR)Show flag, country name, and currency code for clarity.
State Management
Storing Country Selection
Client-side storage (recommended):
- localStorage or cookies
- Persists across sessions
- Key:
region_idorcountry_code
Why local storage:
- Fast access without API call
- Available immediately on page load
- No server round-trip needed
Context Provider Pattern
Recommended: Create context for region/country data.
Provides quick access throughout the app to:
- Selected country
- Selected region (if applicable)
- Currency
- Available payment methods
- Shipping options
Benefits:
- Centralized country/region logic
- Easy access from any component
- Single source of truth
- Simplified cart and product queries
Example structure:
interface RegionContext {
country: string
region?: string
currency: string
changeCountry: (country: string) => void
}When to Apply Selection
Apply country/region to:
- Product price display (convert currency, apply regional pricing)
- Cart creation (set region for accurate totals)
- Product queries (retrieve accurate pricing)
- Checkout flow (shipping methods, payment options)
- Content display (language, measurements)
Backend Integration
General Backend Requirements
What backend needs to provide:
- List of available countries/regions
- Mapping of countries to regions (if using regional structure)
- Pricing per region or country
- Product availability by region
- Shipping methods by region
- Supported payment methods by region
API considerations:
- Fetch country/region list on app load
- Pass selected country/region to product queries
- Include region in cart creation
- Validate country selection on backend
Medusa Backend Integration
For Medusa users, regions are critical for accurate pricing.
Medusa uses regions (not individual countries) for pricing. A region can contain multiple countries.
Key concepts:
- Region: Group of countries with shared pricing (e.g., "Europe" region)
- Country: Individual country within a region
- Currency: Each region has one currency
Mapping country to region: 1. Customer selects country (e.g., "Germany") 2. Find which region contains that country (e.g., "Europe" region) 3. Store region ID for cart and product operations 4. Use region for all pricing queries
Required for:
- Creating carts: Must pass region ID
- Retrieving products: Pass region to get accurate prices
- Product availability: Products may be region-specific
Implementation pattern: Create a context that stores both country and region. When country changes, look up corresponding region and update both.
For detailed Medusa region implementation, see:
- Medusa storefront regions documentation: https://docs.medusajs.com/resources/storefront-development/regions/context
- Medusa JS SDK regions endpoints
- Consult Medusa MCP server for real-time API details
Other backends: Check the ecommerce backend's documentation for country/region handling patterns.
Detection and Defaults
Auto-Detection
IP-based geolocation (recommended): Detect user's country from IP address. Use as default but allow user to change.
Implementation:
- Use geolocation API or service (MaxMind, ipapi.co, CloudFlare)
- Server-side detection (more accurate)
- Set as default, show confirmation: "Shipping to United States?"
Benefits: Reduces friction, most users keep detected country.
Tradeoff: Not 100% accurate (VPNs, proxies). Always allow manual override.
Fallback Strategy
If detection fails or unavailable: 1. Check localStorage for previous selection 2. Use browser language as hint (navigator.language) 3. Default to primary market (e.g., US for US-based store) 4. Prompt user to select on first interaction (cart, checkout)
Never block browsing if country unknown. Allow browsing with default pricing, prompt selection before checkout.
Mobile Considerations
Selector placement: Mobile hamburger menu or bottom of page. Top-right in mobile header if space allows.
Modal selector: Full-screen modal on mobile for country selection. Large touch targets (48px), search input at top, easy scrolling.
Sticky reminder: Small banner: "Shipping to US? Change" with tap to open selector.
Detection prompt: Bottom sheet: "We detected you're in Germany. Is this correct?" with Confirm/Change buttons.
Checklist
Essential features:
- [ ] Country selector visible (header, footer, or first-visit modal)
- [ ] Current country clearly displayed (flag, name, currency)
- [ ] Dropdown or modal with country list
- [ ] Search functionality for long country lists
- [ ] Popular countries at top of list
- [ ] Flag icons for visual recognition
- [ ] Show currency code per country
- [ ] localStorage persistence (save selection)
- [ ] Context provider for region/country data
- [ ] Auto-detection based on IP (optional)
- [ ] Manual override always available
- [ ] Apply to product prices (currency, regional pricing)
- [ ] Apply to cart creation (set region)
- [ ] Apply to checkout (shipping, payment methods)
- [ ] Fallback if detection fails
- [ ] Mobile: Full-screen modal or bottom sheet
- [ ] Mobile: Large touch targets (48px)
- [ ] Backend integration (fetch regions, map countries)
- [ ] For Medusa: Region context with country-to-region mapping
- [ ] For Medusa: Pass region to cart and product queries
- [ ] ARIA label on selector button
- [ ] Keyboard accessible (Tab, Enter, arrows)
- [ ] Screen reader announces country changes
Optional enhancements:
- [ ] Currency conversion display (show original + converted)
- [ ] Language selector tied to country
- [ ] Shipping estimate based on country
- [ ] Tax estimation display
- [ ] Regional content (images, messaging)
- [ ] "Not shipping to your country?" alternative
Footer Component
Contents
- Overview
- Essential Footer Elements
- Dynamic Category Links (Ecommerce-Specific)
- Newsletter Signup
- Payment and Trust Badges
- Mobile Footer
Overview
Footer provides supplementary navigation, company info, and trust signals. Appears on every page.
Assumed knowledge: AI agents know how to build multi-column layouts and navigation lists. This guide focuses on ecommerce footer patterns.
Key Requirements
- Navigation links (categories, pages)
- Dynamic category fetching from backend
- Legal links (Privacy, Terms)
- Newsletter signup
- Payment method badges
- Social media links
- Responsive (multi-column desktop, single-column mobile)
Essential Footer Elements
Must-Have Content
Required:
- Navigation links (categories from backend)
- Contact information (email, phone)
- Legal links (Privacy Policy, Terms of Service)
- Copyright notice with current year
Strongly recommended:
- Newsletter signup form
- Payment method badges
- Social media links
- Trust signals
Multi-Column Layout (Desktop)
Standard pattern: 4-5 columns
- Column 1: Shop/Categories (dynamic from backend)
- Column 2: Customer Service (Contact, FAQ, Shipping)
- Column 3: Company (About, Careers)
- Column 4: Newsletter signup
- Bottom: Legal links, payment badges, copyright
Dynamic Category Links (Ecommerce-Specific)
CRITICAL: Fetch categories from backend dynamically - never hardcode. Fetch from ecommerce backend API (for Medusa: sdk.store.category.list()).
Benefits:
- Stays in sync with main navigation
- Categories added/removed automatically
- No manual footer updates
Guidelines:
- Show top-level categories only (5-8 max)
- Match labels from main navigation
- Cache category data (rarely changes)
Newsletter Signup
Essential elements:
- Email input + submit button ("Subscribe")
- Value proposition (CRITICAL): State clear benefit ("Get 10% off your first order", "Exclusive deals + early access"). Don't just say "Subscribe to newsletter".
- Privacy note: "We respect your privacy" + link to privacy policy
Layout: Input + button inline (desktop), stacked (mobile). Full width on mobile.
Payment and Trust Badges
Payment method icons: Display accepted payments (Visa, Mastercard, PayPal, Apple Pay, Google Pay). 40-50px icons, horizontal row, bottom of footer.
Trust badges (optional): Max 3-4 legitimate certifications (SSL, BBB, money-back guarantee). Only use real badges with verification links.
Mobile Footer
Single column, stacked: Logo → Navigation → Newsletter → Social → Legal/copyright.
Collapsible sections (optional): Accordion pattern for navigation to reduce height. Keep newsletter/social always visible.
Touch-friendly: 44px minimum links, 8-12px spacing, 14-16px text, 48px newsletter input height.
Checklist
Essential features:
- [ ] Navigation links (categories, pages)
- [ ] Categories fetched dynamically from backend
- [ ] Contact information (email, phone)
- [ ] Legal links (Privacy Policy, Terms of Service)
- [ ] Copyright notice with current year
- [ ] Newsletter signup form with value proposition
- [ ] Payment method icons
- [ ] Social media links
- [ ] Responsive (4-5 columns desktop, single-column mobile)
- [ ] Mobile: 44px touch targets
- [ ] Mobile: Collapsible sections (optional)
- [ ] Semantic HTML (
<footer>,<nav>sections) - [ ] ARIA labels on navigation ("Footer navigation")
- [ ] Keyboard accessible
- [ ] Visible focus indicators
- [ ] Color contrast 4.5:1 minimum
- [ ] Consistent across all pages
Hero Section Component
Contents
- Overview
- Hero Types and When to Use
- Content Guidelines
- Multiple Heroes (Carousel)
- Mobile Hero
- Performance
- Checklist
Overview
Hero section is the prominent banner at top of homepage, immediately below navigation. First content users see - sets tone for shopping experience.
Assumed knowledge: AI agents know how to build full-width banners with images and text overlays. This focuses on ecommerce hero patterns.
Key requirements:
- Above the fold (immediately visible)
- Clear value proposition or promotional message
- High-quality imagery
- Strong call-to-action
- Fast loading (critical for first impression)
Hero Types and When to Use
1. Full-Width Banner (Most Common)
Characteristics:
- Spans entire viewport width
- Large background image or video
- Text overlay with headline + CTA
- Single focused message
Best for:
- Seasonal campaigns ("Summer Sale")
- New product arrivals
- Brand storytelling
- Single promotional focus
- Simple, bold message
Example: Background image of products, headline "40% Off Summer Sale", CTA "Shop Now"
2. Split Hero (Image + Content)
Characteristics:
- 50/50 or 60/40 split layout
- Image on one side, text content on other
- No text overlay on image
- Cleaner, easier to read
Best for:
- Product launches (show product clearly)
- Detailed messaging (more text space)
- Accessibility (no text-on-image contrast issues)
- Professional/B2B stores
Example: Product image (left 50%), headline + benefits + CTA (right 50%)
3. Minimal Hero
Characteristics:
- Large image, minimal text
- Image does storytelling
- Subtle headline, small CTA
- Emphasis on visual brand
Best for:
- Luxury brands (sophisticated aesthetic)
- Lifestyle brands (aspirational imagery)
- Photography-focused products
- Brand over promotion
4. Video Hero
Characteristics:
- Background video (muted, looping)
- Text overlay on video
- Fallback image for slow connections
Best for:
- Fashion brands (show products in motion)
- Lifestyle products (demonstrate usage)
- High-budget campaigns
- Brand storytelling with motion
Important: Auto-play muted, provide play/pause controls, optimize file size (<5MB), use poster image fallback.
5. Product Showcase Hero
Characteristics:
- Multiple featured products in hero
- Grid of 2-4 products
- Quick links to product pages
- Less promotional, more discovery
Best for:
- Multi-category stores
- Product-focused (not campaign-focused)
- Quick product discovery
- Minimal marketing, maximum browsing
Content Guidelines
Headline best practices:
- Short and impactful (5-10 words)
- Clear value proposition ("Free Shipping on All Orders")
- Urgency if time-sensitive ("48-Hour Flash Sale")
- Benefit-focused ("Upgrade Your Style")
- Avoid generic ("Welcome to Our Store")
Subtext (optional):
- 10-20 words maximum
- Expand on headline benefit
- Add context or details
- Not always necessary (clean design)
Call-to-action:
- Single primary CTA button
- Action-oriented text ("Shop Now", "Explore Category", "Get Started")
- High contrast (stands out on image)
- Large enough (48px height minimum)
- Link to relevant landing page (sale, category, product listing)
Image selection:
- High quality, professional photography
- Shows products or lifestyle context
- Represents brand aesthetic
- Optimized for web (<500KB)
- Responsive (different crops for mobile)
- Ensure text overlay is readable (adequate contrast)
Multiple Heroes (Carousel)
Carousel pattern:
- 2-4 slides rotating automatically
- Each slide = independent hero (own message, image, CTA)
- Auto-rotate every 5-7 seconds (slow enough to read)
- Manual controls (prev/next arrows, dot indicators)
- Pause on hover (accessibility)
When to use carousel:
- Multiple concurrent campaigns (Winter Sale + New Arrivals)
- Different audience segments (Men/Women/Kids)
- Seasonal variety showcase
- Limited above-fold space
When NOT to use carousel:
- Single focused campaign (just use one hero)
- Users rarely see slides beyond first (carousel blindness)
- Slower page load (multiple images)
- Accessibility concerns (auto-rotating content)
Carousel best practices:
- Max 3-4 slides (more = ignored)
- First slide most important (most viewed)
- Consistent layout across slides
- Clear indicators showing progress
- Don't rely on later slides for critical info
- Pause on interaction (hover, focus)
Mobile Hero
Mobile adjustments (CRITICAL):
Layout:
- Full-width, portrait aspect (2:3 or 3:4)
- Vertical composition (text overlays center/bottom)
- Larger text for readability
- Simplified message (shorter headline)
Split hero on mobile:
- Stack vertically (image top, text bottom)
- Don't use side-by-side (too cramped)
Performance:
- Smaller images (<300KB)
- Different image crop for mobile portrait
- Use
srcsetor<picture>for responsive images - Consider static image instead of video (mobile data)
Touch interactions:
- Large CTA button (48px height minimum)
- Easy carousel controls (if used)
- Swipe gesture for carousel slides
Performance
Critical for first impression:
Image optimization:
- WebP format with JPEG fallback
- Lazy load below-fold content (not hero - it's above fold)
- Responsive images (mobile gets smaller size)
- Target: <500KB desktop, <300KB mobile
- Use CDN for faster delivery
Video optimization:
- <5MB file size maximum
- Muted, autoplay, loop
- Poster image (shows before video loads)
- Fallback to image on slow connections
- Consider not using on mobile (data/performance)
LCP optimization:
- Hero image is often Largest Contentful Paint
- Preload hero image:
<link rel="preload" as="image" href="hero.jpg"> - Inline critical CSS for hero
- Avoid layout shift (set image dimensions)
Target metrics:
- LCP < 2.5 seconds
- No layout shift (CLS < 0.1)
- Fast interaction (hero CTA clickable immediately)
Checklist
Essential features:
- [ ] Above the fold (immediately visible)
- [ ] Clear headline (5-10 words, value proposition)
- [ ] High-quality image (professional, on-brand)
- [ ] Primary CTA button (action-oriented, high contrast)
- [ ] Fast loading (<500KB image desktop, <300KB mobile)
- [ ] Responsive images (different sizes/crops for devices)
- [ ] Mobile: Portrait aspect ratio (2:3 or 3:4)
- [ ] Mobile: Vertical text placement (center/bottom)
- [ ] Mobile: Large CTA (48px height minimum)
- [ ] Text overlay readable (adequate contrast, background overlay)
- [ ] If carousel: Max 3-4 slides
- [ ] If carousel: Auto-rotate 5-7 seconds
- [ ] If carousel: Pause on hover/focus
- [ ] If carousel: Manual controls (arrows, dots)
- [ ] If video: Muted, autoplay, loop
- [ ] If video: Poster image fallback
- [ ] If video: <5MB file size
- [ ] Preload hero image (LCP optimization)
- [ ] No layout shift (set image dimensions)
- [ ] ARIA labels on carousel controls
- [ ] Keyboard accessible (Tab to CTA, arrow keys for carousel)
Megamenu Component
Contents
- Overview
- When to Use Megamenu
- Content Organization
- Layout Patterns
- Trigger Behavior
- Mobile Alternative
- Checklist
Overview
Megamenu is a large, full-width dropdown navigation showing multiple columns of categories, links, and promotional content. Opens from navbar trigger items (e.g., "Shop", "Men", "Women").
Assumed knowledge: AI agents know how to build dropdown menus with hover/click triggers. This focuses on ecommerce megamenu patterns.
Key requirements:
- Full-width display (spans viewport)
- Multiple columns for categories
- Positioned directly below navbar
- Optional promotional images
- Mobile alternative (hamburger menu, not megamenu)
When to Use Megamenu
Use megamenu when:
- Large product catalog (10+ top-level categories)
- Deep hierarchy (parent → child → grandchild levels)
- Want to showcase featured products/campaigns
- Multiple segments (Men, Women, Kids, etc.)
- Visual storytelling needed
Use simple dropdown when:
- Small catalog (<10 categories)
- Flat category structure (1-2 levels)
- Text-only navigation sufficient
- Minimalist design preference
Common megamenu triggers:
- "Shop" (all categories)
- "Men", "Women", "Kids" (segmented)
- "New Arrivals" (curated)
- "Sale" (promotional)
Content Organization
Backend Integration (CRITICAL):
Fetch categories dynamically from ecommerce backend - never hardcode categories. Categories change frequently (new products, seasonal updates, inventory changes). Fetch from API on component mount or during SSR.
Column structure (3-5 columns recommended):
Column 1-3: Category columns
- Parent category header (bold, non-clickable or clickable to "View All")
- Child categories below (clickable links)
- 5-10 links per column maximum
- Group related subcategories
Example:
Electronics (header)
Laptops
Desktops
Monitors
Accessories
View All ElectronicsColumn 4-5: Promotional/Featured
- Product image card (1-2 featured products)
- Campaign banner ("Summer Sale", "New Arrivals")
- "Shop the Look" curated sets
- Seasonal promotions
Content limits:
- Max 5 columns (avoid overcrowding)
- Max 10 links per column
- 1-2 promotional images maximum
- Keep height reasonable (<600px)
Layout Patterns
⚠️ CRITICAL: Megamenu Positioning (Common Mistake)
Common positioning errors that MUST be avoided:
❌ Mistake 1: Navbar doesn't have `position: relative`
- Without positioning context on navbar, megamenu won't position correctly
- Megamenu will position relative to document body instead of navbar
❌ Mistake 2: Megamenu positioned relative to trigger button
- Causes megamenu to appear offset, not aligned to left edge
- Megamenu won't span full width of navbar
- Different trigger positions cause inconsistent megamenu placement
❌ Mistake 3: Megamenu doesn't span full width
- Using
width: autoor no width constraint - Missing
left: 0andright: 0properties - Results in narrow dropdown instead of full-width panel
---
REQUIRED positioning pattern:
Visual structure:
┌─────────────────────────────────────────────────┐
│ NAVBAR (position: relative) │
│ [Logo] [Shop ▼] [Men] [Women] [Cart] │
└─────────────────────────────────────────────────┘
┌───────────────────────────────────────────────┐
│ MEGAMENU (absolute, left: 0, full width) │
│ ┌─────────────────────────────────────────┐ │
│ │ Container (centered content) │ │
│ │ [Col1] [Col2] [Col3] [Promo] │ │
│ └─────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘Required structure:
1. Navbar container
- MUST have
position: relative - Creates positioning context for megamenu
- Contains both trigger button and megamenu dropdown
2. Megamenu dropdown
- MUST have
position: absolute - MUST have
left: 0(aligns to left edge of navbar) - MUST have
right: 0ORwidth: 100%(spans full navbar width) - MUST have
top: 100%(positioned directly below navbar) - Should have appropriate
z-index(above content, below modals)
3. Content wrapper (inside megamenu)
- Use constrained width container (e.g.,
max-width,container) - Center content with
margin: 0 auto - Contains grid/columns for megamenu content
Why this pattern is mandatory:
- Navbar
position: relativecreates positioning context - Megamenu
absolute+left: 0+ full width ensures consistent, full-width layout - Positioning relative to navbar (not trigger) prevents offset issues
- Inner container centers content while maintaining full-width background
---
Other Layout Considerations
- Positioned below navbar (no gap)
- White/light background, boxed padding
- Shadow or border for depth
- High z-index (above page content, below modals)
Column layout:
- Equal-width columns or flexible grid
- Adequate spacing (24-32px between columns)
- Left-aligned text in category columns
- Right column(s) for promotional content
- Responsive: Stack columns on tablet if needed
Promotional images:
- Right-aligned (1-2 columns)
- Aspect ratio: 2:3 or square
- Product images or lifestyle photography
- Clickable to product/category page
- Include caption or CTA ("Shop Now")
Trigger Behavior
Desktop hover (recommended):
- Megamenu opens on trigger hover
- CRITICAL: Megamenu MUST stay open while hovering over the dropdown content
- Stays open while hovering trigger OR dropdown area
- Closes only when mouse leaves both trigger and dropdown areas
- Debounce close (200-300ms delay) to prevent accidental closure
- Smooth fade-in/out transition (200-300ms)
Why this is critical:
- If dropdown closes when moving from trigger to content, users can't access links
- Frustrating UX - users can't interact with megamenu items
- Common mistake: Only listening for hover on trigger, not on dropdown
Desktop click (alternative):
- Click trigger to toggle open/close
- Click outside to close
- Better for touch-enabled laptops
- Less accidental openings
Hover flickering prevention:
- No gap between navbar and dropdown
- Dropdown should slightly overlap navbar
- Debounce close delay prevents flickering
Mobile Alternative
Do NOT use megamenu on mobile:
- Too large for mobile screens
- Hard to navigate multi-column layout
- Poor touch experience
Mobile alternative (hamburger menu):
- Hamburger icon opens slide-in drawer
- Vertical accordion for categories
- Parent category expands to show children
- Simple, scrollable list
- See navbar.md for mobile navigation patterns
Breakpoint:
- Megamenu: Desktop only (>1024px)
- Hamburger: Tablet and mobile (<1024px)
Checklist
Essential features:
- [ ] Triggered from navbar items ("Shop", segments)
- [ ] CRITICAL: Navbar container has `position: relative` (creates positioning context)
- [ ] CRITICAL: Megamenu has `position: absolute` with `left: 0` (NOT positioned relative to trigger button)
- [ ] CRITICAL: Megamenu spans full width (`right: 0` or `w-full`, NOT just `w-auto`)
- [ ] CRITICAL: Megamenu positioned at `top: 100%` or `top-full` (directly below navbar)
- [ ] Full-width dropdown below navbar, spans entire navbar width
- [ ] 3-5 columns for organization
- [ ] Category hierarchy (parent → children links)
- [ ] Optional promotional images (1-2)
- [ ] CRITICAL: Megamenu stays open when hovering over dropdown content (not just trigger)
- [ ] Hover trigger with debounced close (200-300ms)
- [ ] Smooth fade-in/out transition
- [ ] No flickering (no gap between navbar and dropdown)
- [ ] Mobile: Use hamburger menu, NOT megamenu
- [ ] Keyboard accessible (Tab through links, Escape closes)
- [ ]
role="navigation"on dropdown panel - [ ] ARIA labels on trigger buttons
- [ ] Screen reader friendly (announce expand/collapse)
- [ ] Max 10 links per column
- [ ] Max 5 columns total
- [ ] Fetched dynamically from backend (don't hardcode categories)
Navbar Component
Contents
- Overview
- Decision: Simple Dropdown vs Megamenu
- Key Ecommerce Patterns
- Layout Structure
- Accessibility Essentials
- Common Ecommerce Mistakes
- Backend Integration
- Checklist
Overview
Primary navigation for ecommerce storefronts. Desktop: horizontal menu with category links. Mobile: hamburger drawer with accordion subcategories.
⚠️ CRITICAL: NEVER Hardcode Categories
ALWAYS fetch categories dynamically from the backend. NEVER hardcode static category arrays.
❌ WRONG - DO NOT DO THIS:
// WRONG - Static hardcoded categories
const categories = [
{ name: "Women", href: "/categories/women" },
{ name: "Men", href: "/categories/men" },
{ name: "Accessories", href: "/categories/accessories" }
]✅ CORRECT - Fetch from backend:
// CORRECT - Fetch categories dynamically
const [categories, setCategories] = useState([])
useEffect(() => {
fetch(`${apiUrl}/store/product-categories`)
.then(res => res.json())
.then(data => setCategories(data.product_categories))
}, [])Why this matters:
- Categories change frequently (new categories, renamed, reordered)
- Hardcoded categories become outdated immediately
- Requires code changes every time categories change
- Cannot scale to stores with dynamic catalogs
- Defeats the purpose of headless commerce
Key Requirements
- Desktop: Horizontal category links, cart/account/search right-aligned
- Mobile: Hamburger drawer, cart stays visible in header (not hidden in drawer)
- CRITICAL: Fetch categories from backend dynamically (NEVER hardcode static arrays)
- Sticky: Recommended for easy cart access while browsing
- Real-time updates: Cart count, login state, category changes
Decision: Simple Dropdown vs Megamenu
Use Simple Dropdown when:
- <10 top-level categories
- Flat or shallow hierarchy (1-2 levels deep)
- Minimal subcategories per parent
- Focused/specialized product catalog
Use Megamenu when:
- 10+ top-level categories
- Deep hierarchy (3+ levels)
- Need to showcase featured products in navigation
- Complex product catalog
- Fashion, electronics, or large inventory
Mobile: Always use drawer with accordion pattern, never megamenu on mobile.
See megamenu.md for megamenu implementation details.
Key Ecommerce Patterns
Cart Indicator (CRITICAL)
Always visible on both desktop and mobile:
- Desktop: Top-right, cart icon + count badge
- Mobile: Top-right in header (NOT hidden in hamburger drawer)
- This is non-negotiable - users expect cart always accessible
Badge display:
- Shows item count (NOT price - confusing when variants change)
- Only visible when cart has items (count > 0)
- Show actual count up to 99, then "99+"
- Position: Top-right corner of cart icon
- ARIA label:
aria-label="Shopping cart with 3 items"
Real-time updates:
- Update count immediately when items added (optimistic UI)
- No page refresh required
- Sync with backend cart state
- Handle errors gracefully (restore count if add fails)
Click behavior:
- Option 1: Navigate to cart page
- Option 2: Open cart popup/drawer (see cart-popup.md)
- Choice depends on store type (see cart-popup.md for decision criteria)
✅ CORRECT:
- Cart icon visible in mobile header
- Badge shows count (not price)
- Updates in real-time without page refresh
- 44x44px touch target
- Links to cart or opens cart popup
❌ WRONG:
- Hiding cart in mobile hamburger drawer (users can't find it)
- Showing price in badge (€25.99) instead of count
- Cart count doesn't update until page refresh
- No visual feedback when items added
Category Navigation
CRITICAL: Fetch dynamically from backend (NEVER hardcode):
❌ WRONG - These are all incorrect approaches:
// WRONG - Hardcoded array
const categories = ["Women", "Men", "Kids", "Accessories"]
// WRONG - Static object array
const categories = [
{ id: 1, name: "Women", slug: "women" },
{ id: 2, name: "Men", slug: "men" }
]
// WRONG - Importing static data
import { categories } from "./categories.ts"✅ CORRECT - Fetch from backend API:
- Medusa: Use SDK category list method (verify exact method with docs/MCP)
- Other backends: Call categories endpoint (check API documentation)
- Fetch on component mount or during server-side rendering
Why dynamic fetching is mandatory:
- Store owners add/remove/rename categories frequently
- Category order and hierarchy changes
- Multi-language stores need translated category names
- Featured categories rotate (seasonal, promotions)
- Hardcoded values require developer intervention for simple changes
Caching strategy:
- Cache categories (revalidate on interval or manual trigger)
- Use SWR, TanStack Query, or framework-level caching
- Revalidate every 5-10 minutes or on page navigation
- Update immediately when backend categories change
Organization:
- 4-7 top-level categories ideal (max 10 on desktop)
- Order comes from backend (respects admin's ordering)
- Keep "Sale" or "New Arrivals" prominent if backend provides it
- Maximum 2 levels in simple dropdown (category → subcategory)
- Deeper hierarchies: Use megamenu or separate category pages
Desktop behavior:
- Horizontal links with hover dropdowns for subcategories
- Slight hover delay to prevent accidental triggers
- Click parent to navigate to category page
- Click child to navigate to subcategory
Mobile behavior:
- All categories in hamburger drawer
- Accordion pattern for subcategories (expand/collapse)
- Close drawer on category click (except expanding accordion)
- Scrollable drawer if categories exceed viewport height
✅ CORRECT:
- Categories fetched from backend API on mount
- Cache with revalidation strategy
- Respects backend ordering and hierarchy
- 4-7 top-level items on desktop (based on what backend returns)
- Accordion for mobile subcategories
- Consistent ordering across devices
❌ WRONG:
- Hardcoded category array in component (NEVER DO THIS)
- Static categories imported from file (NEVER DO THIS)
- No cache invalidation (stale categories)
- Too many top-level items (>10, overwhelming)
- Different category order on desktop vs mobile
- Categories don't update when backend changes
User Account Indicator
Two states based on authentication:
Logged out:
- Desktop: "Sign In" or "Log In" text + user icon
- Mobile: User icon only
- Click navigates to login page
- Clear call-to-action
Logged in:
- Desktop: User name, initials, or email + dropdown
- Mobile: User name/initials or icon → account page
- Dropdown menu (desktop): My Account, Orders, Wishlist, Sign Out
- Fetch current user from backend authentication state
Authentication state management:
- Check auth state from backend (not just localStorage)
- Update immediately on login/logout events
- Handle session expiration gracefully
- Sync across tabs if possible
✅ CORRECT:
- Shows "Sign In" when logged out
- Shows user identifier when logged in
- Dropdown with account actions
- Checks backend auth state (not just client state)
❌ WRONG:
- No indication of login state
- Relies solely on localStorage (can be stale)
- No dropdown for account actions when logged in
- Missing logout option
Mobile Navigation Pattern
Hamburger drawer:
- Trigger: Hamburger icon (top-left)
- Drawer: Slides from left, 80-85% width, full height, scrollable
- Backdrop: Semi-transparent overlay, click to close
- Content: All categories with accordion subcategories
CRITICAL: Keep cart in header:
- Cart icon stays in mobile header (top-right)
- Don't hide cart inside drawer
- Users expect cart always accessible
- Same for search icon if using icon-only search
Account in drawer:
- Logged out: "Sign In" link in drawer header or top of menu
- Logged in: User name/initials in drawer header with link to account
Close behavior:
- Close button (X) in drawer header
- Click backdrop overlay
- Navigate to category (drawer closes)
- Escape key
✅ CORRECT:
- Cart stays in mobile header (visible)
- Hamburger opens drawer from left
- Backdrop overlay dims background
- Close on navigation or backdrop click
- Scrollable drawer for long menus
❌ WRONG:
- Cart hidden inside hamburger drawer (cardinal sin)
- Full-screen drawer (no backdrop)
- Drawer doesn't close on navigation
- Not scrollable (categories cut off)
Bottom Navigation (Alternative for Mobile)
When to use:
- Store has 3-5 key sections (Home, Browse, Cart, Account, Search)
- App-like experience desired
- Frequent switching between sections
- Not suitable for complex category hierarchies
Pattern:
- Fixed bar at bottom of screen (mobile only)
- Icon + label for each section
- Highlight active section
- 5 items maximum
- Direct navigation, no dropdowns
Layout Structure
Desktop:
- Left: Logo → Homepage
- Center: Category links (horizontal)
- Right: Search, Account, Cart
Mobile:
- Left: Hamburger
- Center: Logo
- Right: Cart (+ Search icon optional)
Sticky recommended:
- Keeps cart/account accessible while scrolling
- Use
position: stickyorposition: fixed - Solid background color (hide scrolling content)
- Adequate z-index to stay above content
Accessibility Essentials
Ecommerce-specific ARIA:
- Cart count:
aria-live="polite"to announce changes (e.g., "3 items in cart") - Mobile drawer:
role="dialog",aria-modal="true" - Hamburger button:
aria-label="Open navigation menu",aria-expanded="false" - Active page:
aria-current="page"on current category link - Dropdown indicators:
aria-expanded,aria-controlsfor megamenu relationships
Keyboard navigation:
- Tab through all links/buttons
- Enter/Space to activate
- Escape to close mobile menu or dropdowns
- Visible focus indicators (outline/ring)
Generic accessibility applies:
- Semantic HTML (
<header>,<nav>) - Icon buttons need ARIA labels
- 4.5:1 color contrast minimum
- 44x44px touch targets on mobile
Common Ecommerce Mistakes
❌ CRITICAL: Hardcoded static categories - NEVER create static category arrays like const categories = ["Women", "Men"] or import from static files. ALWAYS fetch from backend API. Categories change constantly - new categories added, names changed, ordering updated. Hardcoded categories require developer intervention for simple changes and defeat the purpose of dynamic commerce platforms. This is the #1 most common mistake.
❌ Hiding cart in mobile drawer - Users expect cart always visible. Keep cart icon in header (top-right), not hidden inside hamburger menu.
❌ No real-time cart updates - Update count immediately when items added (optimistic UI). Don't require page refresh.
❌ Showing price in cart badge - Show item count (number), not total price. Price display confuses when variants have different quantities.
❌ No cache invalidation - Categories become stale when backend changes. Revalidate periodically (5-10 min) or on manual trigger.
❌ Hover-only dropdowns on mobile - Use click/tap interactions. Hover doesn't work on touch devices.
❌ Desktop navigation on mobile - Use hamburger drawer pattern, not horizontal menu that doesn't fit.
❌ Inconsistent category order - Same order on desktop and mobile for consistency. Respect backend's category ordering.
Backend Integration
Category Fetching (CRITICAL - NEVER Hardcode)
Implementation patterns:
Client-side fetching:
- Fetch categories in useEffect on mount
- Store in state (use appropriate types for Medusa: StoreProductCategory)
- Handle loading and error states
- Map categories to navigation links
- Use category.id as key, category.handle for URL, category.name for display
With caching (RECOMMENDED):
- Use TanStack Query with queryKey ['categories']
- Set staleTime: 5-10 minutes (categories rarely change)
- Automatic loading/error states
- Request deduplication if multiple components need categories
Server-side fetching:
- Fetch in server component or load function
- No loading state needed (rendered on server)
- Better for SEO
Cart state synchronization pattern:
- Subscribe to global cart state (Context)
- Update navbar cart count when cart changes
- Handle optimistic updates (show new count immediately on add to cart)
- Sync with backend on events or interval
Authentication state pattern:
- Check auth state from backend on mount
- Listen for login/logout events
- Update account indicator immediately
- Handle session expiration gracefully
Category update triggers:
- On page load/navigation
- On manual refresh trigger
- On revalidation interval (5-10 minutes)
- After admin updates categories (webhook or polling)
Checklist
Essential navbar features:
- [ ] CRITICAL: Categories fetched dynamically from backend API (NOT hardcoded arrays)
- [ ] CRITICAL: No static category imports or hardcoded category lists
- [ ] Desktop: Horizontal category links
- [ ] Mobile: Hamburger drawer with accordion
- [ ] Cart icon visible on both desktop and mobile header (NOT hidden in drawer)
- [ ] Cart badge shows item count (not price)
- [ ] Cart count updates in real-time
- [ ] Categories use backend ordering (not manual ordering)
- [ ] Account indicator shows login state
- [ ] Logo links to homepage
- [ ] 4-7 top-level categories displayed (max 10)
- [ ] Mobile drawer closes on navigation
- [ ] Sticky navigation (recommended)
- [ ] 44x44px minimum touch targets
- [ ] ARIA labels on icon buttons
- [ ]
aria-liveon cart count for screen readers - [ ] Keyboard accessible with visible focus states
- [ ] Categories cached with revalidation strategy (5-10 min)
- [ ] Error handling for failed category fetch
Popups Component
Contents
- Overview
- When to Use Popups
- Ecommerce Popup Types
- Timing and Triggers
- Frequency Management
- Mobile Considerations
- Checklist
Overview
Popups (modals/overlays) appear over main content to capture attention for specific actions: newsletter signups, promotional offers, exit-intent offers.
Assumed knowledge: AI agents know how to build modals with close buttons and backdrop overlays. This focuses on ecommerce popup patterns.
Critical balance: Effective for conversions when used sparingly, intrusive and annoying when overused. Timing and frequency are critical for ecommerce.
When to Use Popups
Use popups when:
- Offering significant value (10-20% first-purchase discount, free shipping)
- Time-sensitive promotions (flash sale ending soon)
- Exit-intent to recover abandoning visitors (last chance offer)
- First-time visitor welcome (one-time only)
- Important announcements (shipping delays, policy changes)
Don't use popups for:
- Every page visit (extremely annoying)
- Multiple popups per session
- Immediate page load (users haven't seen site yet)
- Mobile users (especially full-screen takeovers - very disruptive)
- Users who already signed up or dismissed
Consider alternatives:
- Top banner: Less intrusive, always visible, good for ongoing promotions
- Inline forms: Homepage or footer newsletter signup, non-blocking
- Slide-in (corner): From bottom-right, less disruptive than center popup
- Post-purchase: Ask for email after successful order (high conversion)
Popups are best when: Need immediate attention, high-value offer justifies interruption, exit-intent (last chance).
Ecommerce Popup Types
1. First-Purchase Discount
Purpose: Convert first-time visitors with discount incentive.
Content:
- Headline: "Welcome! Get 10% Off Your First Order"
- Email input
- Discount code or automatic application
- Subscribe button: "Get My Discount"
Timing: After 30-60 seconds on site OR after viewing 2-3 products (engagement signal).
Frequency: Once per user (cookie/localStorage). Don't show to returning customers.
2. Newsletter Signup
Purpose: Grow email list for marketing.
Content:
- Value proposition: "Get exclusive deals and early access"
- Email input
- Subscribe button
- Optional: First-purchase discount incentive (10-15% off)
Timing: After 50% scroll OR 60 seconds on site.
Frequency: Once per session. If dismissed, don't show for 30 days.
3. Exit-Intent Popup
Purpose: Recover abandoning visitors with last-chance offer.
Trigger: Mouse moves toward browser close/back button (desktop only).
Content:
- Urgency: "Wait! Don't Miss Out"
- Offer: "Take 10% Off Your Order" or "Free Shipping Today Only"
- Email capture (optional): "Send me the code"
- CTA: "Claim Offer" or "Continue Shopping"
Best for: Cart abandoners, product page exits, first-time visitors.
Frequency: Once per session. Don't show if user already added to cart or on checkout.
4. Cart Abandonment Reminder
Purpose: Remind user of items in cart before leaving.
Trigger: Exit-intent when cart has items but user navigating away.
Content:
- "Your Cart is Waiting"
- Show cart summary (items, total)
- CTA: "Complete Your Order" or "View Cart"
- Optional incentive: "Complete in 10 minutes for free shipping"
Frequency: Once per session with items in cart.
5. Promotional Announcement
Purpose: Announce sales, new arrivals, or site-wide events.
Content:
- Headline: "Flash Sale: 40% Off Everything"
- Subtext: "Ends in 3 hours"
- CTA: "Shop Now"
Timing: Immediate on page load (if major event), OR after 30 seconds.
Frequency: Once per day during promotion period.
Timing and Triggers
Time-based:
- 30-60 seconds after page load (enough time to browse)
- Never immediate (0 seconds) - users need to see site first
Engagement-based:
- After 50% scroll (shows interest)
- After viewing 2-3 products (qualified visitor)
- After adding to cart (exit-intent only)
Exit-intent:
- Mouse moves toward close/back button (desktop)
- Scroll-up toward address bar (mobile - less reliable)
- Only trigger once per session
- Don't trigger on checkout pages (interrupts purchase)
Page-specific:
- Homepage: Welcome/discount popup
- Product pages: Exit-intent with product-specific offer
- Cart page: Don't use popups (already engaged)
- Checkout: Never use popups (critical flow)
Frequency Management
Critical for UX: Don't show same popup repeatedly to same user.
Implementation:
1. Cookie/localStorage tracking: Store dismissal/signup with timestamp 2. Respect dismissals: If user closes popup, don't show for 30 days 3. Signed-up users: Never show newsletter popup again 4. Session limits: Max 1 popup per session 5. Time cooldown: If dismissed, wait 30 days before showing again
Example tracking:
// On popup dismiss
localStorage.setItem('popup_dismissed', Date.now())
localStorage.setItem('popup_type', 'welcome_discount')
// Before showing popup
const dismissedTime = localStorage.getItem('popup_dismissed')
const daysSince = (Date.now() - dismissedTime) / (1000 * 60 * 60 * 24)
if (daysSince < 30) {
// Don't show popup
}Progressive disclosure:
- Session 1: Welcome discount popup
- Session 2+: Exit-intent only (if applicable)
- Never stack multiple popups
Mobile Considerations
Mobile popups are MORE intrusive:
- Smaller screen = popup takes more space
- Harder to close (small X button)
- Disrupts mobile browsing flow
- Can hurt mobile SEO (Google penalty for intrusive interstitials)
Mobile best practices:
1. Use sparingly: Consider top banner or inline forms instead 2. Make easily dismissable: Large close button (44x44px), tap outside to close 3. Delay longer: 60+ seconds instead of 30 seconds 4. Smaller size: 90% width max, not full-screen 5. Exit-intent: Less reliable on mobile, avoid 6. Google penalty: Avoid full-screen popups on mobile (hurts rankings)
Mobile alternative: Sticky bottom bar (less intrusive)
- "Get 10% Off - Sign Up" with email input
- Always visible but doesn't block content
- Better mobile UX than popup
Checklist
Essential features:
- [ ] Clear value proposition (discount, benefit)
- [ ] Single focused CTA
- [ ] Easy to close (X button, backdrop click, Escape key)
- [ ] Delayed timing (30-60s, not immediate)
- [ ] Frequency management (localStorage/cookie tracking)
- [ ] Respect dismissals (30-day cooldown)
- [ ] Never show to signed-up users
- [ ] Max 1 popup per session
- [ ] Exit-intent for cart abandoners (desktop only)
- [ ] Don't show on checkout pages
- [ ] Mobile: Use sparingly, consider alternatives
- [ ] Mobile: Large close button (44x44px)
- [ ] Mobile: Not full-screen (90% width max)
- [ ] Email validation before submit
- [ ] Loading state on submit
- [ ] Success message or redirect
- [ ] Keyboard accessible (Tab, Escape, Enter)
- [ ]
role="dialog"andaria-modal="true" - [ ] Focus trap (keep focus within popup)
- [ ] ARIA label on close button
- [ ] Screen reader announcements on open
Product Card Component
Contents
- Overview
- Price Display (Ecommerce-Specific)
- Action Buttons and Variant Handling
- Badges and Labels
- Mobile Considerations
- Ecommerce Checklist
Overview
Product cards display products in grids (product listings, search results, related products). Key ecommerce considerations: clear pricing, quick add-to-cart, and stock indicators.
Assumed knowledge: AI agents know how to build cards with images, titles, and buttons. This guide focuses on ecommerce-specific patterns.
Key Ecommerce Requirements
- Clear, prominent pricing (including sale prices)
- Variant handling for add-to-cart
- Stock status indicators
- Sale/New/Out of Stock badges
- Responsive grid (1 col mobile, 2-3 tablet, 3-4 desktop)
- Fast image loading (lazy load, optimized)
Price Display (Ecommerce-Specific)
Regular vs Sale Pricing
Sale price display:
- Sale price: Larger, bold, red or accent color
- Original price: Smaller, struck through (~~$79.99~~), gray
- Position sale price before original price
- Optional: Show discount percentage badge (-20%)
Format consistently:
- Always include currency symbol ($49.99)
- Consistent decimals ($49.99 not $49.9 or $50)
- For Medusa: Display prices as-is (no divide by 100)
Price Range (Multiple Variants)
When variants have different prices:
- Show "From $49" or "$49 - $79"
- Makes it clear price varies by selection
- Don't show range if all variants same price
Action Buttons and Variant Handling
Add to Cart with Variants (CRITICAL)
Key challenge: Products with variants require variant selection before adding to cart.
Handling strategies:
1. Add first variant by default - Click adds product.variants[0]. Fast for simple products (1-2 variants). 2. Redirect to product page - Navigate to detail page for variant selection. Best for complex products (size + color + material). 3. Quick View modal - Variant selector in modal. Good middle ground (desktop only).
Decision:
- Simple products (1-2 variants): Add first variant
- Fashion/apparel with sizes: Require size selection (redirect or Quick View)
- Complex products (3+ variant types): Redirect to product page
Button behavior:
- Loading state ("Adding..."), disable during loading
- Optimistic UI update (cart count immediately)
- Success feedback (toast, cart popup, or checkmark)
- Don't navigate away (stay on listing page)
- Handle errors (out of stock, API failure)
Wishlist button (optional): Heart icon, top-right over image. Empty when not saved, filled (red) when saved. Refer to wishlist.md for more details.
Badges and Labels
Badge priority (show max 1-2 per card):
1. Out of Stock (highest) - Gray/black overlay on image, disables add-to-cart 2. Sale/Discount - "Sale" or "-20%", red/accent, top-left corner 3. New - "New" for recent products, blue/green, top-left corner 4. Low Stock (optional) - "Only 3 left", orange, creates urgency
Display: Top-left corner (except Out of Stock overlay), small but readable, high contrast.
Mobile Considerations
Grid Layout
Mobile-specific adjustments:
- 2 columns maximum on mobile (never 3+)
- Larger touch targets (44px minimum for buttons)
- Always show "Add to Cart" button (no hover-only)
- Simplified content (hide optional elements like brand)
- Smaller images for performance (<400px wide)
Touch Interactions
No hover states on mobile:
- Don't hide actions behind hover
- Always show primary button
- Use tap states (active state) instead of hover
Ecommerce Checklist
Essential features:
- [ ] Clear product image (optimized, lazy loaded)
- [ ] Product title (truncated to 2 lines max)
- [ ] Price prominently displayed
- [ ] Sale price shown correctly (struck-through original price)
- [ ] Currency symbol included
- [ ] For Medusa: Price displayed as-is (not divided by 100)
- [ ] Add to Cart button with loading state
- [ ] Variant handling strategy (first variant, redirect, or Quick View)
- [ ] Optimistic UI update (cart count immediately)
- [ ] Success feedback (toast or cart popup)
- [ ] Don't navigate away after adding to cart
- [ ] Out of Stock badge (disables add-to-cart)
- [ ] Sale badge when price reduced
- [ ] Responsive grid (1 col mobile, 2-3 tablet, 3-4 desktop)
- [ ] Touch-friendly on mobile (44px buttons)
- [ ] Keyboard accessible (focus states, Enter to activate)
- [ ] Descriptive alt text on images
- [ ] Semantic HTML (
<article>wrapper)
Product Reviews Component
Contents
- Overview
- Review Display Patterns
- Rating Summary and Distribution
- Sorting and Filtering
- Review Submission
- Trust Signals
- SEO Integration
Overview
Product reviews build trust and influence purchase decisions. Reviews with ratings convert 270% better than products without.
Assumed knowledge: Claude knows how to build forms and display lists. This guide focuses on ecommerce review patterns and trust signals.
Key Requirements
- Star rating summary (1-5 stars) with distribution
- Individual reviews with ratings, text, author, date
- Sorting (Most Recent, Most Helpful, Highest/Lowest Rating)
- Filtering by rating (5 stars only, 4+ stars)
- Verified purchase badges
- Helpful votes (upvote system)
- Review submission form
- Mobile-optimized
Review Display Patterns
Placement
On product page:
- Below product details (after add-to-cart)
- Before related products
- Anchor link in product info: "★★★★★ (127 reviews)"
Separate reviews page:
- Only for very large catalogs (500+ reviews)
- Link: "View All Reviews"
- Most stores show reviews inline on product page
Rating Summary and Distribution
Average Rating Display
Show prominently:
- Average rating: "★★★★★ 4.5 out of 5"
- Total review count: "Based on 127 reviews"
- Large stars (24-32px)
Rating Distribution (CRITICAL)
Visual breakdown with clickable bars:
5 ★ [████████████████████] 82 (65%)
4 ★ [██████░░░░░░░░░░░░░░] 25 (20%)
3 ★ [██░░░░░░░░░░░░░░░░░░] 10 (8%)
2 ★ [█░░░░░░░░░░░░░░░░░░░] 5 (4%)
1 ★ [█░░░░░░░░░░░░░░░░░░░] 5 (3%)Make bars clickable:
- Click to filter reviews by rating
- Shows only selected star ratings
- "Show all" to reset filter
Why distribution matters:
- Perfect 5.0 rating seems fake (customers trust 4.2-4.5 average)
- Showing negative reviews builds trust
- Distribution helps customers understand product quality
No Reviews State
When no reviews:
- "No reviews yet"
- "Be the first to review this product"
- "Write a Review" button prominent
- Don't show 0 stars or empty rating
Sorting and Filtering
Sort Options (CRITICAL)
Essential sorting:
- Most Recent (default) - shows latest feedback
- Most Helpful (by upvotes) - surfaces best reviews
- Highest Rating (5 stars first) - see positive feedback
- Lowest Rating (1 star first) - see concerns
Dropdown selector:
Sort by: [Most Recent ▾]Filter Options
Filter by rating:
- All ratings (default)
- 5 stars only
- 4+ stars
- 3 stars or less (see negative feedback)
Filter by criteria:
- Verified purchases only (highest trust)
- With photos only (visual proof)
- Recent (last 30 days, 6 months)
Show filtered count:
- "Showing 24 of 127 reviews"
Review Submission
Review Form Fields
Required:
- Star rating (1-5 stars selector)
- Review text (textarea, 50-500 characters)
- Reviewer name (if not logged in)
Optional:
- Review title/headline
- Upload images (2-5 max)
- Would you recommend? (Yes/No)
Form placement:
- "Write a Review" button opens modal or inline form
- Position near rating summary
Form Validation
Requirements:
- Rating must be selected
- Minimum review length (50 characters)
- Show character counter: "50 / 500 characters"
- Validate before submit
Success:
- "Thank you for your review!"
- "Your review is pending approval" (if moderation enabled)
Trust Signals
Verified Purchase Badge (CRITICAL)
Display:
- Badge or checkmark: "✓ Verified Purchase"
- Position near reviewer name
- Green color or checkmark icon
- Only for confirmed customers
Why it matters:
- Builds trust (real customer, not fake)
- Reduces suspicion of paid reviews
- Higher credibility
Helpful Votes
Upvote/downvote system:
- "Was this review helpful?"
- [👍 Yes (24)] [👎 No (2)]
- Click to vote (one vote per user)
- Powers "Most Helpful" sorting
Benefits:
- Surfaces most useful reviews
- Community validation
- Reduces impact of unhelpful reviews
Review Images (Optional)
Customer-uploaded photos (3-4 max per review, 60-80px thumbnails, click to enlarge). Visual proof increases trust and engagement.
Store Responses (Recommended)
Seller replies below original review (indented, light gray background). Respond to negative reviews professionally - shows you care, addresses concerns without being defensive.
SEO Integration
AggregateRating Schema (CRITICAL): Add structured data to show star ratings in search results. Include ratingValue (avg rating), reviewCount, bestRating (5), worstRating (1).
SEO benefits: Star ratings in search results, higher CTR, rich snippets. See seo.md for implementation details.
Important: Only include if reviews are real. Fake reviews violate Google guidelines.
Display Patterns
Individual review card: Star rating (16-20px) + text + reviewer name (first name + initial) + date + verified badge + helpful votes. Truncate long reviews (200-300 chars) with "Read more".
Mobile: Single column, touch-friendly votes (44px), full-screen sort select, filter bottom sheet, "Load more" pagination.
Checklist
Essential features:
- [ ] Star rating summary (average + count)
- [ ] Rating distribution bar chart (5 to 1 stars)
- [ ] Clickable bars to filter by rating
- [ ] Sort dropdown (Most Recent, Most Helpful, Highest/Lowest)
- [ ] Filter options (verified, with photos, by rating)
- [ ] Individual reviews with: stars, text, name, date
- [ ] Verified purchase badge
- [ ] Helpful votes (upvote/downvote)
- [ ] Review submission form (rating, text)
- [ ] Form validation (minimum length, required rating)
- [ ] "Read more" for long reviews
- [ ] Store responses to reviews (recommended)
- [ ] Review images (customer uploads, optional)
- [ ] Mobile: Touch targets 44px minimum
- [ ] Pagination or "Load more" button
- [ ] No reviews state ("Be the first to review")
- [ ] AggregateRating structured data (SEO)
- [ ] ARIA labels for star ratings
- [ ] Keyboard accessible (all interactions)
Product Slider Component
Contents
- Overview
- When to Use Product Sliders
- Slider Patterns
- Product Display
- Navigation Controls
- Mobile Sliders
- Performance
- Checklist
Overview
Product slider (carousel) displays multiple products horizontally with navigation to scroll through them. Used for related products, recently viewed, bestsellers, and featured products.
Assumed knowledge: AI agents know how to build carousels with navigation. This focuses on ecommerce product slider patterns.
Key requirements:
- Horizontal scrolling of product cards
- Arrow navigation (prev/next)
- Optional dot indicators
- Mobile: Swipe gesture support
- Responsive product count (4-6 visible desktop, 2-3 mobile)
- Lazy loading for off-screen products
When to Use Product Sliders
Use for:
- Related products (product page)
- Recently viewed (product page, homepage)
- "You May Also Like" (product page)
- Bestsellers / Featured products (homepage)
- "Frequently Bought Together" (product page)
- New arrivals (homepage)
- Category showcases (homepage)
Don't use for:
- Main product images (use gallery instead)
- Critical content (not all users scroll/swipe)
- Checkout flow (keep linear)
- Primary navigation (use grid for discoverability)
Slider Patterns
Continuous scroll:
- Shows 4-6 products at once (desktop)
- Scroll left/right by 1-2 products at a time
- Smooth animated transition (300-400ms)
- Most common pattern
Infinite loop (optional):
- Wraps to beginning after end
- Good for small product sets (<10 items)
- Creates continuous browsing feel
- Not necessary for large sets
Snap to alignment:
- Products snap to grid after scroll
- Prevents partial product visibility
- Better visual alignment
- Improves browsing experience
Auto-play (NOT recommended for products):
- Automatic scrolling without user action
- Poor UX for product sliders (users lose control)
- Only use for promotional banners/hero images
- If using: Pause on hover, slow speed (5-7s)
Product Display
Product cards in sliders:
- Same cards as product grids (see product-card.md)
- Simplified on mobile (less detail, smaller images)
- Image, title, price minimum
- Optional: Rating, "Add to Cart" (desktop only)
- Adequate spacing between cards (16-24px)
Responsive display:
- Large desktop (>1440px): 5-6 products visible
- Desktop (1024-1440px): 4-5 products
- Tablet (768-1024px): 3-4 products
- Mobile (<768px): 2 products (sometimes 1.5 for scroll hint)
Scroll hint on mobile:
- Show 1.5 products (partial visibility of next)
- Indicates more content to swipe
- Improves discoverability
- Better than showing exact 2 products
Navigation Controls
Arrow buttons:
- Left/right arrows outside slider
- Desktop: Always visible or show on hover
- Mobile: Hidden (swipe gesture preferred)
- Position: Vertically centered
- Size: 40-48px touch targets
- Disable left arrow at start, right arrow at end (no infinite loop)
Dot indicators (optional):
- Show progress through slider
- Each dot = one "page" of products
- Position: Below slider, centered
- Small (8-12px dots)
- Only if many products (>12)
- Less common for product sliders (more for hero carousels)
Keyboard navigation:
- Tab through visible product cards
- Arrow keys scroll slider (optional)
- Focus management on scroll
Mobile Sliders
Touch gestures:
- Horizontal swipe to scroll
- Native scroll momentum
- Snap to product alignment
- No arrow buttons (swipe is intuitive)
Mobile-specific adjustments:
- 2 products visible (or 1.5 for hint)
- Larger touch targets on products
- Remove hover-only features (Quick View)
- Faster scroll animations (200-300ms)
Performance on mobile:
- Lazy load off-screen products
- Smaller image sizes
- Limit initial products loaded (8-10)
- Load more on scroll
Performance
Lazy loading (critical):
- Only load visible products initially
- Load adjacent products (left/right) on demand
- Significantly improves page load time
- Use Intersection Observer API
Image optimization:
- Responsive images (smaller for mobile)
- WebP format with fallback
- Lazy load off-screen images
- Optimized thumbnails (<300KB)
Limit slider length:
- Max 20-30 products per slider
- "View All" link to full category page
- Improves performance
- Prevents endless scrolling
Checklist
Essential features:
- [ ] 4-6 products visible (desktop), 2 (mobile)
- [ ] Arrow navigation (desktop)
- [ ] Swipe gesture (mobile)
- [ ] Product cards with image, title, price
- [ ] Responsive product count
- [ ] Smooth scroll transitions (300-400ms)
- [ ] Snap to product alignment
- [ ] Lazy load off-screen products
- [ ] "View All" link if many products (>20)
- [ ] Disable arrows at start/end
- [ ] Keyboard accessible (Tab through products)
- [ ] Mobile: No arrows, swipe only
- [ ] Optimized images (<300KB)
- [ ] Spacing between products (16-24px)
- [ ] ARIA labels on navigation (
aria-label="Previous products") - [ ]
role="region"on slider container - [ ] NO auto-play for product sliders
Search Component
Contents
- Overview
- Search Placement
- Autocomplete and Product Suggestions
- Search Results Page
- Empty States
- Recent and Popular Searches
- Mobile Search
Overview
Search is critical for ecommerce - users with search intent convert at higher rates. Provide fast, relevant product discovery with autocomplete.
Assumed knowledge: AI agents know how to build search inputs with icons and clear buttons. This guide focuses on ecommerce search patterns.
Key Requirements
- Prominent search input (always accessible)
- Instant autocomplete after 2-3 characters
- Product suggestions with images
- Fast, relevant search results
- Filters to refine results
- Empty state guidance
- Mobile full-screen search modal
Search Placement
Desktop: Navbar center (between logo and cart) or right side. Always visible, 300-500px width. Part of sticky navbar. Never hide in hamburger menu.
Mobile: Magnifying glass icon in top-right (44x44px minimum). Opens full-screen modal - eliminates distractions, maximizes suggestion space, better typing experience.
Autocomplete and Product Suggestions
Show suggestions after 2-3 characters (not 1). Debounce 300ms to prevent excessive API calls.
Display 5-10 product suggestions:
- Small image (40-60px), title, price
- Clickable to product page
- Optional: Category/brand suggestions, popular terms
- Divide sections with headers
- "View all results for [query]" footer link
Backend integration: Fetch from search API. Check with ecommerce platform's documentation for API reference.
Search Results Page
Header: "Search Results for '[query]'" + result count ("24 products found"). Search bar visible and pre-filled for refining.
Grid layout: Same as product listings (see product-listing.md). 1-4 columns based on device.
Sorting: Relevance (default, unique to search), Price Low/High, Newest.
Filters: Sidebar (desktop) or drawer (mobile). Category, Price, Brand, Availability with result counts.
Empty States
No results: "No results for '[query]'" with helpful suggestions (check spelling, try broader keywords, browse categories). "Browse All Products" button + links to popular categories.
Loading state: Product card skeletons (6-8 cards), minimum 300ms display to avoid flashing.
Recent and Popular Searches
Recent searches (user-specific, localStorage): Show 3-5 recent searches when input focused (before typing). Helps re-search without retyping.
Popular searches (site-wide, from backend): Show 5-10 trending terms when focused. Pill/tag styling.
Display both on: Empty input focus (desktop dropdown), mobile modal open.
Mobile Search
Full-screen modal pattern:
- Header: Back button (44x44px) + search input (48px height, auto-focus,
type="search") - Content: Recent/popular searches (empty), autocomplete (typing), scrollable
- Close: Back button, device back gesture, Escape key
Ecommerce Search Checklist
Essential features:
- [ ] Prominent search input in navbar (desktop)
- [ ] Search icon clearly visible (mobile)
- [ ] Full-screen modal on mobile tap
- [ ] Autocomplete after 2-3 characters
- [ ] Debounced API calls (300ms)
- [ ] Product suggestions with images, prices
- [ ] "View all results" link in dropdown
- [ ] Search results page shows query
- [ ] Result count displayed
- [ ] Sort by Relevance (default for search)
- [ ] Filters for refining results (category, price, brand)
- [ ] Empty state with helpful guidance
- [ ] Loading state indicator (skeleton)
- [ ] Recent searches (localStorage)
- [ ] Popular searches (from backend)
- [ ] Mobile: Auto-focus, large input (48px)
- [ ] Keyboard navigation (arrow keys, Enter, Escape)
- [ ] ARIA labels (
role="search",aria-label) - [ ] Accessible to screen readers
Connecting to Backend
Contents
- Overview
- Detecting the Backend
- Framework Detection
- Environment Configuration
- Backend-Specific Integration
- Authentication Patterns
- Cart State Management
- Error Handling for Ecommerce
- Performance Patterns
- Data Fetching with TanStack Query
- Checklist
Overview
Best practices for connecting storefront to ecommerce backend APIs. Framework-agnostic patterns for authentication, cart state management, error handling, and performance optimization.
For Medusa-specific integration, see reference/medusa.md for SDK setup, pricing, regions, and Medusa patterns.
Detecting the Backend (CRITICAL)
Before implementing any backend integration, identify which ecommerce backend is being used.
Detection Strategy
1. Check for monorepo structure:
# Look for backend directory
ls -la ../backend
ls -la ./backend
ls -la ../../apps/backendCommon monorepo patterns:
/apps/storefront+/apps/backend/frontend+/backend/packages/web+/packages/api
2. Check package.json dependencies:
{
"dependencies": {
"@medusajs/js-sdk": "...", // Medusa
// check other ecommerce frameworks...
}
}3. Check environment variables:
# Look in .env, .env.local, .env.example
grep -i "api\|backend\|medusa\|shopify\|commerce" .env*Common patterns:
NEXT_PUBLIC_MEDUSA_BACKEND_URL→ Medusa- Custom
API_URLorBACKEND_URL→ Other backend
4. If unsure, ASK THE USER:
I need to connect to the ecommerce backend. Which backend are you using?
Options:
- Medusa (open-source headless commerce)
- Custom backend
- OtherBackend Documentation and MCP Servers
ALWAYS refer to the backend's official documentation or MCP server for:
- API endpoints and data structures
- Authentication requirements
- SDK usage and installation
- Environment configuration
- Rate limits and best practices
For Medusa:
- Documentation: https://docs.medusajs.com
- MCP Server: If available, use Medusa MCP server for real-time API information
- JS SDK docs: https://docs.medusajs.com/resources/js-sdk
- See
reference/medusa.mdfor detailed integration guide
For other backends:
- Check the backend's documentation portal
- Look for MCP server if available
- Verify API endpoints and authentication methods
- Never assume API structure without verification
Important: Do not guess API endpoints or data formats. Always verify with documentation or ask the user to confirm the backend's API structure.
Framework Detection
Identify the frontend framework to determine appropriate data fetching patterns:
Next.js:
- App Router: Server Components (async/await), Client Components (useEffect/TanStack Query)
- Pages Router: getServerSideProps/getStaticProps (server), useEffect (client)
SvelteKit:
- Load functions for server-side data
- Client-side: fetch in component lifecycle
TanStack Start:
- Server functions for server-side data
- Client-side: fetch with React hooks
General Rule:
- Server-side for initial load: SEO, performance, security (product pages, listings)
- Client-side for interactions: Cart, filters, search, user-specific data
Environment Configuration
Store API URLs and keys in environment variables:
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_PUBLISHABLE_KEY=pk_...Framework-specific prefixes:
- Next.js:
NEXT_PUBLIC_for client-side - SvelteKit:
PUBLIC_for client-side - Vite-based (TanStack Start):
VITE_for client-side
Security:
- ❌ NEVER expose secret/admin keys in client-side code
- ✅ Publishable keys are safe for client (Medusa, Stripe)
- ✅ Secret keys only in server-side code or environment
Backend-Specific Integration
Medusa Backend
For complete Medusa integration guide, see reference/medusa.md which covers:
- SDK installation and setup
- Vite configuration (for TanStack Start, etc.)
- TypeScript types from
@medusajs/types - Price display (never divide by 100)
- Common operations (products, cart, categories, customers)
- Custom endpoints
- Region state management
- Error handling with SDK
Other Backends
For non-Medusa backends (custom APIs, third-party platforms):
1. Consult backend's API documentation for:
- Authentication requirements
- Available endpoints
- Request/response formats
- SDK availability (check if official SDK exists)
2. Use backend's official SDK if available - provides type safety, error handling, and best practices
3. If no SDK, create API client wrapper:
- Centralize API calls in one module
- Group by resource (products, cart, customers, orders)
- Handle authentication (include tokens/cookies)
- Handle errors consistently
- Use native fetch or axios
Authentication Patterns
Customer Authentication
Session-based (cookies):
- Backend manages session via cookies
- No manual token management needed
- Works across page refreshes
- Common in traditional ecommerce backends
- Call backend login endpoint, check auth state, logout methods
Token-based (JWT, OAuth):
- Store token in localStorage or secure cookie after login
- Include token in Authorization header for all authenticated requests
- Common in headless/API-first backends
- Format:
Authorization: Bearer {token}
Protecting Customer Routes
Check authentication before rendering customer-specific pages (account, orders, addresses):
- Server-side: Check auth in server functions (getServerSideProps, load functions, etc.). Redirect to login if not authenticated.
- Client-side: Check auth state on mount. Redirect to login if not authenticated.
Use framework-specific auth patterns for redirects.
Cart Access Pattern
Guest carts:
- Store cart ID in localStorage or cookie
- Check for existing cart ID on app load
- Create new cart if none exists
- Allows shopping without account
- Persists across sessions
Logged-in carts:
- Associate cart with customer account
- Syncs across devices
- CRITICAL: Merge guest cart with customer cart on login - Transfer guest cart items to customer's account cart, then clear guest cart ID from localStorage
Cart State Management
Critical ecommerce pattern: Cart must be accessible throughout the app.
Global Cart State
React Context (for simple cases):
- Create CartContext and CartProvider
- Store cart state and cartId (from localStorage)
- Load cart on mount if cartId exists
- Provide methods: addItem, removeItem, updateQuantity, clearCart
- Update cart state after each operation
State management libraries (Zustand, Redux):
- Use for complex state requirements
- Better for large applications
- Easier to debug with DevTools
- Same pattern: Store cart, provide actions, sync with backend
Key requirements:
- Cart accessible from any component
- Real-time cart count updates
- Optimistic UI updates (update UI immediately, sync with backend)
Cart Cleanup After Order Placement (CRITICAL)
IMPORTANT: After order is successfully placed, you MUST reset the cart state.
Common issue: Cart popup and global cart state still show old items after order completion. This happens when cart state isn't cleared after checkout.
Required cleanup actions:
1. Clear cart from global state - Reset cart state to null/empty in Context/Zustand/Redux 2. Clear localStorage cart ID - Remove cart ID: localStorage.removeItem('cart_id') 3. Invalidate cart queries - If using TanStack Query: queryClient.invalidateQueries({ queryKey: ['cart'] }) 4. Update cart count to 0 - Navbar and UI should reflect empty cart
When to clear:
- After successful order placement (order confirmed)
- On navigation to order confirmation page
- Before redirecting to thank you page
Why this is critical:
- Prevents "phantom cart" from appearing in cart popup after order
- Ensures clean state for next shopping session
- Improves UX by not showing old cart items
Error Handling for Ecommerce
Ecommerce-Specific Errors
Out of stock:
- Catch errors when adding to cart
- Check for "out of stock" or "inventory" in error message
- Show user-friendly message: "Sorry, this item is now out of stock"
- Update product availability UI to show out of stock
Price changed during checkout:
- Compare cart total with expected total
- If different, show warning: "Prices have been updated. Please review your cart."
- Highlight changed prices in cart
Payment failed:
- Catch errors during order completion
- Check for specific payment errors: payment_declined, insufficient_funds, etc.
- Show specific messages:
- Payment declined → "Payment declined. Please try a different payment method."
- Insufficient funds → "Insufficient funds. Please use a different card."
- Generic → "Payment failed. Please try again or contact support."
Session expired:
- Catch 401/Unauthorized errors
- Clear auth state
- Redirect to login with message: "Your session has expired. Please log in again."
User-Friendly Error Messages
Transform technical errors to clear messages:
- Network/fetch errors → "Unable to connect. Please check your internet connection."
- Timeout errors → "Request timed out. Please try again."
- Inventory errors → "This item is no longer available in the requested quantity."
- Generic fallback → "Something went wrong. Please try again or contact support."
Pattern: Check error message or status code, map to user-friendly message, show in UI (toast, banner, inline).
Performance Patterns
Data Fetching with TanStack Query (RECOMMENDED)
Use TanStack Query for all backend API calls - provides automatic caching, request deduplication, loading/error states, and optimistic updates.
Installation: npm install @tanstack/react-query
Setup:
- Create QueryClient with default options (staleTime: 5 min, retry: 1)
- Wrap app with QueryClientProvider
Query pattern (for fetching data):
- Use
useQuerywith queryKey and queryFn - queryKey: Array with resource and identifier
['products', categoryId] - queryFn: API call function
- Returns:
data,isLoading,error - Use for: Products, cart, customer data, categories
Mutation pattern (for modifying data):
- Use
useMutationwith mutationFn - mutationFn: API operation (add to cart, update, delete)
- onSuccess: Update cache or invalidate queries
- Returns:
mutatefunction,isPendingstate - Use for: Add to cart, remove from cart, update quantities, place order
Benefits:
- Automatic caching (no manual cache management)
- Built-in loading/error states
- Request deduplication
- Optimistic updates (update UI before server responds)
- Cache invalidation strategies
Ecommerce-specific usage:
- Products: Long stale time (5-10 min) - products don't change often
- Cart: Short or no stale time - prices/inventory can change
- Categories: Long stale time - rarely change
Caching Strategy
Client-side caching:
- TanStack Query handles automatically with
staleTimeandcacheTime - Configure globally or per-query
- Product data: 5-10 min stale time
- Cart data: Fresh on every fetch
- Categories: Long stale time
Server-side caching (framework-specific):
- Next.js: Use
revalidateexport or cache configuration - Set revalidation period (e.g., 300 seconds for product pages)
- Static generation with ISR for product pages
Request Deduplication
TanStack Query and modern frameworks handle this automatically - multiple components requesting same data result in single request.
Pagination Pattern
Offset-based: Pass limit and offset parameters to API limit: 24, offset: page * 24
Cursor-based (better performance): Pass limit and cursor (last item ID) limit: 24, cursor: lastProductId
Check backend documentation for supported pagination type.
Checklist
Essential backend integration:
- [ ] Backend detected (Medusa, Shopify, custom, etc.)
- [ ] Environment variables configured (API URL, keys)
- [ ] Framework-specific data fetching patterns identified
- [ ] RECOMMENDED: TanStack Query installed and configured for API calls
- [ ] Server-side fetching for product pages (SEO)
- [ ] Client-side fetching for cart and user interactions (use TanStack Query)
- [ ] Authentication flow implemented (login/logout)
- [ ] Cart ID persisted in localStorage or cookies
- [ ] Global cart state management (context or store)
- [ ] Cart count synced across app
- [ ] Optimistic UI updates for cart operations
- [ ] Error handling for out of stock scenarios
- [ ] Error handling for payment failures
- [ ] Session expiration handling (redirect to login)
- [ ] User-friendly error messages (not technical)
- [ ] Caching strategy for product data
- [ ] Stock availability checks before checkout
- [ ] Price change detection and warnings
For Medusa backends, also check:
- [ ] Medusa SDK installed (
@medusajs/js-sdk+@medusajs/types) - [ ] SDK initialized with baseUrl and publishableKey
- [ ] Vite SSR config added (if using TanStack Start/Vite)
- [ ] Using official types from
@medusajs/types - [ ] Not dividing prices by 100 (display as-is)
- [ ] Region context implemented for multi-region stores
- [ ] Region passed to cart and product queries
See reference/medusa.md for complete Medusa integration guide.
Design Guidelines
Contents
- Overview
- Discovering Existing Brand Identity
- Critical Consistency Rules
- When to Ask User Approval
- New Project Setup
- Decision Tree
- Common Mistakes
Overview
Purpose: Provide guardrails to maintain brand consistency when building UI components. This prevents agents from accidentally introducing inconsistent colors, fonts, or design patterns.
Critical principle: ALWAYS discover and use existing design tokens before creating new components. NEVER introduce new colors or fonts without user approval.
When to apply: Before creating any UI component or design-related change.
Discovering Existing Brand Identity
Before implementing any component, identify existing brand colors, typography, and design patterns. AI agents can do this - focus on WHAT to look for, not detailed HOW.
What to Look For
Colors: 1. Tailwind config (tailwind.config.ts/js) - Check theme.extend.colors or theme.colors 2. CSS variables (globals.css, app.css) - Look for :root { --color-primary: ... } 3. Existing components - Scan 2-3 components for color usage patterns
Typography: 1. Tailwind config - Check theme.extend.fontFamily 2. Font imports - Look in layout files or CSS (Next.js next/font, Google Fonts, local fonts) 3. CSS variables - Check for --font-sans, --font-heading 4. Existing components - Identify font usage patterns
Other patterns:
- Spacing scale (p-4, mb-6, etc.)
- Border radius (rounded-lg, rounded-xl)
- Shadows (shadow-md, shadow-lg)
- Interactive states (hover, focus colors)
Detecting Tailwind Version (CRITICAL)
ALWAYS check the Tailwind CSS version before writing utility classes.
Tailwind v3 and v4 have different syntax, and mixing them causes errors.
How to detect version: 1. Check `package.json`: Look for "tailwindcss": "^3.x.x" or "tailwindcss": "^4.x.x" 2. Check config file:
- v3: Uses
tailwind.config.js/tswithmodule.exportsorexport default - v4: May use CSS-based config with
@import "tailwindcss"
3. Check existing components: Look at class usage patterns
Key differences:
Tailwind v3:
// v3 syntax
<div className="bg-primary text-white">Content</div>Tailwind v4:
// v4 may use CSS variables differently
// Check the project's existing patterns
<div className="bg-primary text-white">Content</div>Common mistake: Using v3 syntax in v4 projects or vice versa. Always verify the version first.
Document Discovery
Create mental inventory of:
- Primary color(s) and their usage
- Font families (sans, serif, heading, mono)
- Common patterns (button styles, card designs, spacing)
- Semantic names (primary, secondary, accent vs blue-500, red-600)
Critical Consistency Rules
ALWAYS Follow These Rules
✅ NEVER use emojis in storefront UI - Always use icons or images instead
// ✅ CORRECT - Using icon component or image
<button className="flex items-center gap-2">
<ShoppingCartIcon className="w-5 h-5" />
Add to Cart
</button>
// ❌ WRONG - Using emoji
<button>
🛒 Add to Cart
</button>Why: Emojis appear differently across platforms, lack professional appearance, and can cause accessibility issues. Use icon libraries (Heroicons, Lucide, Font Awesome) or SVG images instead.
✅ USE existing design tokens (colors, fonts, spacing from theme)
// ✅ CORRECT - Using theme colors
<button className="bg-primary text-white hover:bg-primary-dark">
Click Me
</button>
// ❌ WRONG - Arbitrary colors when theme exists
<button className="bg-[#3B82F6] text-white hover:bg-[#2563EB]">
Click Me
</button>✅ USE existing font definitions, not new font families
// ✅ CORRECT - Using theme font
<h1 className="font-heading text-4xl font-bold">
Welcome
</h1>
// ❌ WRONG - Introducing new font
<h1 className="font-['Montserrat'] text-4xl font-bold">
Welcome
</h1>✅ MATCH patterns from existing components
// If existing buttons use: bg-primary px-6 py-3 rounded-lg
// New buttons should use the same pattern
<button className="bg-primary px-6 py-3 rounded-lg">
New Button
</button>NEVER Do These Things
❌ DON'T introduce new colors without user approval
- If you need a color not in the theme, ASK first
- Don't use arbitrary values like
bg-[#FF6B6B]when theme has colors
❌ DON'T add new fonts without user approval
- If current design uses Inter, don't add Montserrat without asking
- Don't use
font-['NewFont']syntax when theme fonts exist
❌ DON'T use hard-coded values when theme tokens exist
- Use
bg-primarynotbg-[#3B82F6] - Use
p-6notp-[24px] - Use
font-headingnotfont-['Poppins']
❌ DON'T create inconsistent patterns
- If buttons use
rounded-lg, all buttons should - If cards use
shadow-md, all cards should - If hover effects use
hover:bg-primary-dark, be consistent
When to Ask User Approval
ALWAYS ask before:
1. Adding New Color
"I notice the current palette doesn't include an orange accent color.
Should I add one, or would you prefer to use the existing accent color?"Scenario: You're building a promotional banner that needs an orange color, but theme only has blue/purple.
2. Adding New Font
"The current design uses Inter for all text. Do you want me to add
a different font for headings, or keep using Inter throughout?"Scenario: Building a hero section and wondering if headings should use a different font.
3. Changing Existing Definitions
"Should I update the primary color to #3B82F6, or create a
new color variant?"Scenario: Current primary is #2563EB but new design mockup shows #3B82F6.
4. Creating New Pattern
"The current components don't have a ghost button style (transparent with border).
Should I create one, or use an existing button variant?"Scenario: Need a subtle button style that doesn't exist yet.
DON'T Ask About
❌ Standard web dev decisions (responsive breakpoints, hover effects) ❌ Component structure or layout choices ❌ Accessibility patterns (AI agents know WCAG) ❌ Using existing theme colors/fonts in new ways
New Project Setup
When starting a new project WITHOUT existing theme:
Ask User These Questions
1. Brand Colors:
"What are your brand colors? Please provide:
- Primary color (main brand color)
- Secondary color (optional)
- Any specific hex codes or color preferences?"2. Font Preferences:
"Do you have font preferences?
- Modern and clean (Inter, Poppins)
- Classic and professional (Merriweather, Lora)
- Specific fonts?
- Or should I choose appropriate fonts?"3. Design Style:
"What design style do you prefer?
- Minimal (lots of whitespace, clean lines)
- Bold (vibrant colors, large typography)
- Professional (conservative, trust-focused)
- Modern (rounded corners, gradients, shadows)"4. Reference Sites (Optional):
"Do you have 2-3 example websites you like the look of?
This helps me understand your aesthetic preferences."Setup Theme Configuration
After gathering preferences, configure Tailwind theme:
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
primary: '#3B82F6', // User's primary color
secondary: '#8B5CF6', // User's secondary
accent: '#F59E0B', // Accent if needed
// Full scales if sophisticated design
brand: {
50: '#eff6ff',
500: '#3b82f6',
900: '#1e3a8a',
}
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
heading: ['Poppins', 'sans-serif'],
},
},
},
}Use Tailwind CSS for all new projects - industry standard for ecommerce, highly customizable, excellent DX.
Decision Tree
When creating any component:
1. Does a theme configuration exist?
├─ Yes → Extract colors/fonts from theme
│ Use existing tokens for new component
└─ No → Ask user for brand preferences
Create theme configuration
2. Are there similar existing components?
├─ Yes → Follow their patterns exactly
│ (spacing, colors, hover states)
└─ No → Check ANY existing components
Extract general patterns (spacing scale, hover effects)
3. Do you need a color/font not in theme?
├─ Yes → ASK user for approval before adding
│ Explain why you need it
└─ No → Proceed with existing tokens
4. Are you unsure about a design pattern?
├─ Yes → Check 2-3 existing components for guidance
│ Follow majority pattern
└─ No → Implement using theme tokens
Maintain consistency with existing componentsCommon Mistakes
❌ Using Arbitrary Values When Theme Exists
Problem: Using bg-[#3B82F6] when bg-primary exists.
Why it's wrong: Bypasses theme, creates inconsistency, harder to maintain.
Fix: Always use semantic names from theme.
❌ Introducing New Colors Without Permission
Problem: Adding text-orange-500 when theme doesn't have orange.
Why it's wrong: User may not want orange in their brand, creates color chaos.
Fix: Ask user first: "Should I add an orange color, or use existing accent?"
❌ Not Checking Existing Patterns
Problem: Creating buttons with rounded-full when all other buttons use rounded-lg.
Why it's wrong: Visual inconsistency confuses users.
Fix: Check 2-3 existing buttons, use same rounding.
❌ Adding Fonts Without Permission
Problem: Using font-['Montserrat'] when theme uses Inter everywhere.
Why it's wrong: Fonts are brand identity - can't arbitrarily change.
Fix: Use existing font-heading or font-sans, or ask to add Montserrat.
❌ Using Inline Styles Instead of Theme
Problem: style={{ backgroundColor: '#3B82F6', padding: '24px' }}
Why it's wrong: Bypasses Tailwind theme, not responsive, harder to maintain.
Fix: Use Tailwind classes: bg-primary p-6
❌ Mixing Tailwind v3 and v4 Syntax
Problem: Using Tailwind v3 syntax in a v4 project, or vice versa.
Why it's wrong: Different versions have different configuration and syntax patterns. Mixing them causes build errors and unexpected styling behavior.
Fix: Check package.json for Tailwind version first. Look at existing components to understand the syntax patterns used in the project. Match the version-specific patterns consistently.
❌ Inconsistent Interactive States
Problem: Some buttons use hover:bg-primary-600, others use hover:brightness-110.
Why it's wrong: Inconsistent user experience.
Fix: Check existing buttons, use same hover pattern everywhere.
❌ Creating Theme Changes Without Approval
Problem: Adding new color to tailwind.config.ts without asking.
Why it's wrong: Theme changes affect entire project, need user agreement.
Fix: Ask first, explain rationale, get approval.
Summary Checklist
Before creating any component:
- [ ] Detected Tailwind CSS version (v3 or v4) from package.json
- [ ] Checked for existing theme configuration (Tailwind config or CSS variables)
- [ ] Extracted existing colors and documented them
- [ ] Extracted existing fonts and documented them
- [ ] Reviewed 2-3 existing components for patterns
- [ ] Identified spacing scale, border radius, shadow patterns
- [ ] Confirmed I'm using theme tokens, not arbitrary values
- [ ] Matched hover/focus states from existing components
- [ ] Verified color contrast meets WCAG 2.1 AA (4.5:1 for text) - Use WebAIM Contrast Checker
- [ ] Asked user before adding any new colors or fonts
- [ ] Maintained visual consistency across all components
This is about CONSISTENCY, not creating new designs. Match what exists, ask before changing.
Related skills
Forks & variants (1)
Storefront Best Practices has 1 known copy in the catalog totaling 19 installs. They canonicalize to this original listing.
- medusajs - 19 installs
How it compares
Pick storefront-best-practices over generic frontend skills when building headless ecommerce flows with Medusa-aware cart, checkout, and conversion patterns.
FAQ
Which reference file must load before creating UI components?
Always load reference/design.md first to discover design tokens, colors, fonts, spacing, and brand patterns.
What accessibility rule applies to cart count updates?
Cart count changes require aria-live polite so screen readers announce updates.
What SEO requirement applies to product pages?
Product schema JSON-LD is required for Google Shopping and rich snippet eligibility.
Is Storefront Best Practices safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.