E-commerce Store
A modern, full-featured e-commerce storefront with product grid, shopping cart, checkout flow, and customer account pages. Built for conversion.
Overview
Built for Modern Commerce
This template provides everything you need to launch a professional online store. From product discovery to checkout, every interaction is designed for conversion and customer satisfaction.
Smart Shopping Cart
Persistent cart with real-time updates and quantity management
Streamlined Checkout
Multi-step checkout with progress indicators and form validation
Customer Accounts
User profiles with order history and saved addresses
Mobile-First Design
Responsive layouts optimized for all screen sizes
Live Demo
Summer Essentials
Discover our curated collection of premium products designed for the modern lifestyle.
Featured Products
Premium Headphones
$299
Leather Backpack
$189
Smart Watch
$399
Running Shoes
$149
Wireless Speaker
$129
Sunglasses
$199
Implementation Guide
Set Up Project Structure
Create the necessary pages and components for your e-commerce store.
123456789101112131415161718// Recommended folder structure src/ ├── app/ │ ├── page.tsx # Home/Store page │ ├── products/ │ │ ├── page.tsx # Product listing │ │ └── [id]/page.tsx # Product detail │ ├── cart/page.tsx # Shopping cart │ ├── checkout/page.tsx # Checkout flow │ └── account/ │ ├── page.tsx # Account dashboard │ └── orders/page.tsx ├── components/ │ ├── ProductCard.tsx │ ├── CartDrawer.tsx │ └── CheckoutForm.tsx └── lib/ └── cart-context.tsx # Cart state management
Create Cart Context
Set up global state management for the shopping cart.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465"use client"; import { createContext, useContext, useState, ReactNode } from "react"; interface CartItem { id: string; name: string; price: number; quantity: number; image: string; } interface CartContextType { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; updateQuantity: (id: string, quantity: number) => void; total: number; } const CartContext = createContext<CartContextType | undefined>(undefined); export function CartProvider({ children }: { children: ReactNode }) { const [items, setItems] = useState<CartItem[]>([]); const addItem = (item: CartItem) => { setItems(prev => { const existing = prev.find(i => i.id === item.id); if (existing) { return prev.map(i => i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i ); } return [...prev, { ...item, quantity: 1 }]; }); }; const removeItem = (id: string) => { setItems(prev => prev.filter(i => i.id !== id)); }; const updateQuantity = (id: string, quantity: number) => { if (quantity <= 0) return removeItem(id); setItems(prev => prev.map(i => i.id === id ? { ...i, quantity } : i) ); }; const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0 ); return ( <CartContext.Provider value={{ items, addItem, removeItem, updateQuantity, total }}> {children} </CartContext.Provider> ); } export const useCart = () => { const context = useContext(CartContext); if (!context) throw new Error("useCart must be used within CartProvider"); return context; };
Build Product Grid
Create a responsive product grid with filtering and sorting.
12345678910111213141516171819202122232425262728293031323334interface Product { id: string; name: string; price: number; image: string; category: string; rating: number; } function ProductGrid({ products }: { products: Product[] }) { return ( <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"> {products.map((product) => ( <Link key={product.id} href={`/products/${product.id}`}> <div className="group"> <div className="aspect-square rounded-2xl bg-slate-100 dark:bg-slate-800 overflow-hidden mb-4"> <img src={product.image} alt={product.name} className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" /> </div> <h3 className="font-medium text-slate-900 dark:text-white"> {product.name} </h3> <p className="text-slate-600 dark:text-slate-400"> ${product.price.toFixed(2)} </p> </div> </Link> ))} </div> ); }
Implement Checkout Flow
Build a multi-step checkout with shipping and payment forms.
123456789101112131415161718192021222324252627282930313233function CheckoutForm() { const [step, setStep] = useState(1); const { items, total } = useCart(); return ( <div className="max-w-2xl mx-auto"> {/* Progress indicator */} <div className="flex items-center gap-4 mb-8"> {["Shipping", "Payment", "Review"].map((label, i) => ( <div key={label} className="flex items-center gap-2"> <div className={`w-8 h-8 rounded-full flex items-center justify-center ${ step > i + 1 ? "bg-emerald-500 text-white" : step === i + 1 ? "bg-cyan-600 text-white" : "bg-slate-200 text-slate-500" }`}> {step > i + 1 ? "✓" : i + 1} </div> <span className={`text-sm ${step === i + 1 ? "font-medium" : ""}`}> {label} </span> </div> ))} </div> {/* Step content */} {step === 1 && <ShippingForm onNext={() => setStep(2)} />} {step === 2 && <PaymentForm onNext={() => setStep(3)} onBack={() => setStep(1)} />} {step === 3 && <ReviewOrder items={items} total={total} />} </div> ); }
Full Source Code
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235"use client"; import { useState, createContext, useContext, ReactNode } from "react"; import Link from "next/link"; // Cart Context interface CartItem { id: string; name: string; price: number; quantity: number; image: string; } interface CartContextType { items: CartItem[]; addItem: (item: Omit<CartItem, "quantity">) => void; removeItem: (id: string) => void; updateQuantity: (id: string, quantity: number) => void; total: number; count: number; } const CartContext = createContext<CartContextType | undefined>(undefined); export function CartProvider({ children }: { children: ReactNode }) { const [items, setItems] = useState<CartItem[]>([]); const addItem = (item: Omit<CartItem, "quantity">) => { setItems(prev => { const existing = prev.find(i => i.id === item.id); if (existing) { return prev.map(i => i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i); } return [...prev, { ...item, quantity: 1 }]; }); }; const removeItem = (id: string) => setItems(prev => prev.filter(i => i.id !== id)); const updateQuantity = (id: string, quantity: number) => { if (quantity <= 0) return removeItem(id); setItems(prev => prev.map(i => i.id === id ? { ...i, quantity } : i)); }; const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0); const count = items.reduce((sum, item) => sum + item.quantity, 0); return ( <CartContext.Provider value={{ items, addItem, removeItem, updateQuantity, total, count }}> {children} </CartContext.Provider> ); } export const useCart = () => { const context = useContext(CartContext); if (!context) throw new Error("useCart must be used within CartProvider"); return context; }; // Product Grid Component interface Product { id: string; name: string; price: number; image: string; category: string; rating: number; } function ProductGrid({ products }: { products: Product[] }) { const { addItem } = useCart(); return ( <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"> {products.map((product) => ( <div key={product.id} className="group"> <div className="aspect-square rounded-2xl bg-slate-100 dark:bg-slate-800 overflow-hidden mb-4 relative"> <img src={product.image} alt={product.name} className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" /> <button onClick={() => addItem(product)} className="absolute bottom-4 left-1/2 -translate-x-1/2 px-4 py-2 bg-cyan-600 text-white text-sm font-medium rounded-lg opacity-0 group-hover:opacity-100 transition-opacity" > Add to Cart </button> </div> <div className="flex items-center gap-1 mb-1"> <svg className="w-4 h-4 text-amber-400 fill-current" viewBox="0 0 20 20"> <path d="M10 15l-5.878 3.09 1.123-6.545L.489 6.91l6.572-.955L10 0l2.939 5.955 6.572.955-4.756 4.635 1.123 6.545z" /> </svg> <span className="text-sm text-slate-600 dark:text-slate-400">{product.rating}</span> </div> <h3 className="font-medium text-slate-900 dark:text-white">{product.name}</h3> <p className="text-slate-600 dark:text-slate-400">${product.price}</p> </div> ))} </div> ); } // Header Component function StoreHeader() { const { count } = useCart(); const [cartOpen, setCartOpen] = useState(false); return ( <header className="sticky top-0 z-50 bg-white/80 dark:bg-slate-950/80 backdrop-blur-xl border-b border-slate-200 dark:border-slate-800"> <div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between"> <div className="flex items-center gap-8"> <Link href="/" className="text-xl font-bold text-slate-900 dark:text-white"> ShopCo </Link> <nav className="hidden md:flex items-center gap-6"> {["New", "Women", "Men", "Accessories", "Sale"].map((item) => ( <Link key={item} href={`/${item.toLowerCase()}`} className={`text-sm font-medium ${ item === "Sale" ? "text-red-500" : "text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white" }`} > {item} </Link> ))} </nav> </div> <div className="flex items-center gap-4"> <button className="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg"> <SearchIcon /> </button> <button className="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg"> <UserIcon /> </button> <button onClick={() => setCartOpen(true)} className="relative p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg" > <CartIcon /> {count > 0 && ( <span className="absolute -top-1 -right-1 w-5 h-5 bg-cyan-600 text-white text-xs font-bold rounded-full flex items-center justify-center"> {count} </span> )} </button> </div> </div> {cartOpen && <CartDrawer onClose={() => setCartOpen(false)} />} </header> ); } // Cart Drawer Component function CartDrawer({ onClose }: { onClose: () => void }) { const { items, total, updateQuantity, removeItem } = useCart(); return ( <div className="fixed inset-0 z-50"> <div className="absolute inset-0 bg-black/50" onClick={onClose} /> <div className="absolute right-0 top-0 h-full w-full max-w-md bg-white dark:bg-slate-900 shadow-xl"> <div className="flex items-center justify-between p-6 border-b border-slate-200 dark:border-slate-800"> <h2 className="text-lg font-semibold text-slate-900 dark:text-white">Shopping Cart</h2> <button onClick={onClose} className="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg"> <CloseIcon /> </button> </div> <div className="p-6 space-y-4 max-h-[calc(100vh-200px)] overflow-y-auto"> {items.map((item) => ( <div key={item.id} className="flex gap-4"> <div className="w-20 h-20 rounded-xl bg-slate-100 dark:bg-slate-800 overflow-hidden"> <img src={item.image} alt={item.name} className="w-full h-full object-cover" /> </div> <div className="flex-1"> <h3 className="font-medium text-slate-900 dark:text-white">{item.name}</h3> <p className="text-slate-600 dark:text-slate-400">${item.price}</p> <div className="flex items-center gap-2 mt-2"> <button onClick={() => updateQuantity(item.id, item.quantity - 1)} className="w-8 h-8 rounded-lg border border-slate-200 dark:border-slate-700" > - </button> <span className="w-8 text-center">{item.quantity}</span> <button onClick={() => updateQuantity(item.id, item.quantity + 1)} className="w-8 h-8 rounded-lg border border-slate-200 dark:border-slate-700" > + </button> </div> </div> <button onClick={() => removeItem(item.id)} className="text-slate-400 hover:text-red-500"> <TrashIcon /> </button> </div> ))} </div> <div className="absolute bottom-0 left-0 right-0 p-6 border-t border-slate-200 dark:border-slate-800"> <div className="flex items-center justify-between mb-4"> <span className="text-slate-600 dark:text-slate-400">Subtotal</span> <span className="text-xl font-bold text-slate-900 dark:text-white">${total}</span> </div> <Link href="/checkout"> <button className="w-full py-3 bg-cyan-600 hover:bg-cyan-700 text-white font-medium rounded-xl"> Checkout </button> </Link> </div> </div> </div> ); } // Icon Components function SearchIcon() { return <svg className="w-5 h-5 text-slate-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>; } function UserIcon() { return <svg className="w-5 h-5 text-slate-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg>; } function CartIcon() { return <svg className="w-5 h-5 text-slate-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" /></svg>; } function CloseIcon() { return <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>; } function TrashIcon() { return <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>; }
Customization Guide
Brand Colors
Update the color scheme to match your brand identity.
// Replace cyan with your brand color
// In tailwind.config.ts:
colors: {
brand: {
50: '#f0f9ff',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
}
}
// Then update classes:
// bg-cyan-600 → bg-brand-600Product Card Styles
Customize product card appearance and hover effects.
// Add badges, quick-add buttons, etc.
<div className="group relative">
{product.isNew && (
<span className="absolute top-2 left-2 px-2 py-1 bg-emerald-500 text-white text-xs rounded-full">
New
</span>
)}
{product.discount && (
<span className="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white text-xs rounded-full">
-{product.discount}%
</span>
)}
{/* Quick add button on hover */}
<button className="absolute bottom-4 left-1/2 -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity">
Add to Cart
</button>
</div>Navigation Structure
Customize the header navigation and categories.
const categories = [
{ name: "New Arrivals", href: "/new" },
{ name: "Women", href: "/women",
subcategories: ["Dresses", "Tops", "Pants"]
},
{ name: "Men", href: "/men",
subcategories: ["Shirts", "Jackets", "Shoes"]
},
{ name: "Sale", href: "/sale", highlight: true },
];Payment Integration
Connect with Stripe, PayPal, or other payment providers.
// Example Stripe integration
import { loadStripe } from '@stripe/stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY!);
async function handleCheckout() {
const stripe = await stripePromise;
const { sessionId } = await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ items: cartItems }),
}).then(r => r.json());
await stripe?.redirectToCheckout({ sessionId });
}Ready to Launch Your Store?
Copy this template, customize it to your brand, and start selling. All the components you need are included.