Zenixbase
Next JS Tutorial for Beginners | Temu Clone #1

Next JS Tutorial for Beginners | Temu Clone #1

T
Tech & Beyond
December 16, 202528 min read

Introduction

Welcome to this comprehensive Next.js tutorial! In this complete guide, we're building a Temu clone from scratch to learn modern web development with Next.js, Tailwind CSS, and Shadcn UI.

By the end of this tutorial, you'll have built a complete, production-ready e-commerce website with:

  • A sticky navigation header with search
  • An auto-playing hero carousel
  • Product cards with ratings and discounts
  • Category navigation
  • Multiple product sections (Flash Sale, New Arrivals, Popular Products)
  • A professional footer with links and social media icons

What you'll learn:

  • Setting up a Next.js 16 project with TypeScript
  • Installing and configuring Shadcn UI
  • Creating reusable React components
  • Using Tailwind CSS for responsive design
  • Working with TypeScript interfaces
  • Implementing carousels with autoplay
  • Building layouts with Flexbox and Grid
  • Optimizing images with Next.js Image component

Prerequisites:

  • Node.js 18+ installed
  • Basic understanding of React
  • Familiarity with HTML/CSS
  • A code editor (VS Code recommended)

Let's build an amazing e-commerce website together!


Part 1: Project Setup

First, let's create a new Next.js project. Open your terminal and run:

npx create-next-app@latest temu-web

Note: You can also choose "Recommended defaults".

When prompted, choose these options:

  • TypeScript: Yes
  • ESLint: Yes
  • Tailwind CSS: Yes
  • src/ directory: No
  • App Router: Yes
  • Customize import alias: No (use default @/*)

Now navigate into the project:

cd temu-web

Let's start the development server to make sure everything works:

npm run dev

Open your browser and go to http://localhost:3000. You should see the default Next.js page. Great! Now let's build our Temu clone.


Part 2: Installing and Configuring Shadcn UI

Shadcn UI is a collection of beautifully designed components built with Radix UI and Tailwind CSS. Instead of installing it as a package, we'll add components directly to our project.

Initialize Shadcn UI

Run this command in your terminal:

npx shadcn@latest init

When prompted, choose these options:

  • Style: New York
  • Base color: Neutral
  • CSS variables: Yes

This will create a components.json file and update your Tailwind configuration.

Add Required Components

Now let's add all the Shadcn components we'll need:

npx shadcn@latest add button card input badge

Then add a few more:

npx shadcn@latest add carousel separator avatar

These commands will create component files in components/ui/ folder.

Install Additional Dependencies

We need one more package for the carousel autoplay feature:

npm install embla-carousel-autoplay

Perfect! Now we have everything we need. Let's start building our components!


Part 3: Building the Header Component

The Header is the navigation section at the top of our website. It's one of the most important UI elements.

The Header component is the navigation section at the top of a website. It's one of the most important UI elements because it helps users navigate your site and access key features like search and shopping cart.

In e-commerce websites like Temu, the header typically includes:

  • Logo - Your brand identity
  • Search Bar - Allows users to find products
  • Shopping Cart - Shows items added to cart
  • User Account - Login/profile access
  • Navigation Menu - Links to different sections

Our header will also have a promotional banner at the very top to announce special offers.


Setting Up the Component File

First, let's create our Header component file. In the components folder, create a new file called Header.tsx.

Understanding "use client"

The very first line of our component will be:

"use client";

Why do we need this?

In Next.js 13 and above, components are Server Components by default. This means they render on the server, which is great for performance and SEO. However, when we need interactivity - like click handlers, state management, or browser APIs - we need to tell Next.js to make it a Client Component.

We're using "use client" here because while our Header doesn't have state or click handlers yet, we're using icons and UI components that might need client-side features. It's a good practice for navigation components.


Importing Dependencies

Next, let's import everything we need:

"use client";

import { ShoppingCart, Search, Menu, User, Heart } from "lucide-react";
import { Input } from "./ui/input";
import { Button } from "./ui/button";

Let's break this down:

  1. Lucide React Icons - We're importing 5 icons:

    • ShoppingCart - For the cart button
    • Search - For the search bar
    • Menu - For mobile menu (hamburger icon)
    • User - For user account
    • Heart - For wishlist/favorites
  2. Shadcn UI Components - We're using:

    • Input - For the search field
    • Button - For icon buttons

These Shadcn components were added earlier using npx shadcn@latest add input button.


Creating the Component Structure

Now let's create the basic component structure:

export default function Header() {
  return (
    <header className="sticky top-0 z-50 bg-white border-b shadow-sm">
      {/* Our header content will go here */}
    </header>
  );
}

Understanding the Tailwind Classes:

  • sticky - Makes the header stick to the viewport
  • top-0 - Positions it at the very top (0px from top)
  • z-50 - High z-index to ensure it stays above other content
  • bg-white - White background color
  • border-b - Border at the bottom
  • shadow-sm - Small shadow for depth

This combination creates a professional-looking header that stays visible as users scroll.


Adding the Promotional Banner

Let's add a promotional banner at the top of our header:

export default function Header() {
  return (
    <header className="sticky top-0 z-50 bg-white border-b shadow-sm">
      {/* Top Banner */}
      <div className="bg-gradient-to-r from-orange-500 to-pink-500 text-white text-center py-2 text-sm font-medium">
        🎉 Free shipping on orders over $29 • Shop now and save big!
      </div>
    </header>
  );
}

What's happening here:

  • bg-gradient-to-r - Creates a gradient from left to right
  • from-orange-500 to-pink-500 - Orange to pink gradient (Temu's brand colors)
  • text-white - White text for contrast
  • text-center - Centers the text
  • py-2 - Padding on top and bottom (8px)
  • text-sm - Small text size
  • font-medium - Medium font weight

The emoji 🎉 adds a fun, promotional feel to the banner!


Creating the Main Header Container

Below the banner, we'll create a container for the main header content:

export default function Header() {
  return (
    <header className="sticky top-0 z-50 bg-white border-b shadow-sm">
      {/* Top Banner */}
      <div className="bg-gradient-to-r from-orange-500 to-pink-500 text-white text-center py-2 text-sm font-medium">
        🎉 Free shipping on orders over $29 • Shop now and save big!
      </div>

      {/* Main Header */}
      <div className="container mx-auto px-4 py-3">
        <div className="flex items-center justify-between gap-4">
          {/* Content will go here */}
        </div>
      </div>
    </header>
  );
}

Container Classes Explained:

  • container - Creates a responsive container (max-width based on screen size)
  • mx-auto - Centers the container horizontally (margin-left and margin-right: auto)
  • px-4 - Padding on left and right (16px)
  • py-3 - Padding on top and bottom (12px)

Flex Container:

  • flex - Enables flexbox layout
  • items-center - Vertically centers all child elements
  • justify-between - Spreads items apart (logo left, search center, icons right)
  • gap-4 - Adds 16px spacing between flex items

Building the Logo Section

Now let's add the logo and mobile menu button:

{
  /* Logo */
}
<div className="flex items-center gap-2">
  <Button variant="ghost" size="icon" className="lg:hidden">
    <Menu className="h-6 w-6" />
  </Button>
  <a href="/" className="text-2xl font-bold text-orange-500">
    Temu
  </a>
</div>;

Breaking it down:

Mobile Menu Button:

  • Button variant="ghost" - Shadcn button with transparent background
  • size="icon" - Square button perfect for icons
  • lg:hidden - Only visible on screens smaller than 1024px (mobile/tablet)
  • Menu icon with h-6 w-6 - 24px × 24px hamburger menu icon

Logo Link:

  • href="/" - Links to homepage
  • text-2xl - Large text (24px)
  • font-bold - Bold font weight
  • text-orange-500 - Orange brand color

Creating the Search Bar

The search bar is the centerpiece of our header:

{
  /* Search Bar */
}
<div className="flex-1 max-w-2xl relative">
  <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" />
  <Input
    type="text"
    placeholder="Search for products..."
    className="pl-10 pr-4 py-5 w-full rounded-full border-2 border-gray-200 focus:border-orange-500"
  />
</div>;

Container Classes:

  • flex-1 - Takes up all available space (grows to fill)
  • max-w-2xl - Maximum width of 672px (keeps it from getting too wide)
  • relative - Positions the search icon absolutely within this container

Search Icon:

  • absolute - Positions absolutely within the relative container
  • left-3 - 12px from the left edge
  • top-1/2 - Positioned at 50% from top
  • transform -translate-y-1/2 - Moves up by 50% of its height (perfect vertical centering)
  • text-gray-400 - Light gray color
  • h-5 w-5 - 20px × 20px icon

Input Field:

  • type="text" - Standard text input
  • placeholder - Hint text for users
  • pl-10 - Left padding (40px) to make room for the icon
  • pr-4 - Right padding (16px)
  • py-5 - Top and bottom padding (20px) for height
  • w-full - Full width of container
  • rounded-full - Fully rounded corners (pill shape)
  • border-2 - 2px border
  • border-gray-200 - Light gray border
  • focus:border-orange-500 - Orange border when focused (clicked)

Adding the Action Icons

Now let's add the wishlist, cart, and user icons on the right side:

{
  /* Right Actions */
}
<div className="flex items-center gap-2">
  <Button variant="ghost" size="icon" className="relative">
    <Heart className="h-6 w-6" />
  </Button>
  <Button variant="ghost" size="icon" className="relative">
    <ShoppingCart className="h-6 w-6" />
    <span className="absolute -top-1 -right-1 bg-orange-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
      0
    </span>
  </Button>
  <Button variant="ghost" size="icon">
    <User className="h-6 w-6" />
  </Button>
</div>;

Container:

  • flex items-center gap-2 - Horizontal layout with centered items and 8px gap

Wishlist Button:

  • Simple ghost button with a heart icon

Shopping Cart Button:

  • Ghost button with cart icon
  • relative - Allows absolute positioning of the badge
  • Badge span:
    • absolute -top-1 -right-1 - Positioned slightly outside the button (top-right)
    • bg-orange-500 - Orange background
    • text-white - White text
    • text-xs - Extra small text (12px)
    • rounded-full - Perfect circle
    • h-5 w-5 - 20px × 20px circle
    • flex items-center justify-center - Centers the "0" text inside the circle

User Account Button:

  • Simple ghost button with user icon

Adding the Navigation Menu

Finally, let's add the category navigation menu below the main header:

{
  /* Navigation Menu */
}
<nav className="hidden lg:flex items-center gap-6 mt-4 text-sm">
  <a href="#" className="hover:text-orange-500 font-medium">
    Home
  </a>
  <a href="#" className="hover:text-orange-500">
    Flash Sale
  </a>
  <a href="#" className="hover:text-orange-500">
    Electronics
  </a>
  <a href="#" className="hover:text-orange-500">
    Fashion
  </a>
  <a href="#" className="hover:text-orange-500">
    Home & Garden
  </a>
  <a href="#" className="hover:text-orange-500">
    Sports
  </a>
  <a href="#" className="hover:text-orange-500">
    Toys & Games
  </a>
  <a href="#" className="hover:text-orange-500">
    Beauty
  </a>
</nav>;

Navigation Classes:

  • hidden - Hidden by default (mobile screens)
  • lg:flex - Displays as flex on large screens (1024px+)
  • items-center - Vertically centers links
  • gap-6 - 24px spacing between links
  • mt-4 - Margin top (16px) to separate from header above
  • text-sm - Small text size (14px)

Links:

  • hover:text-orange-500 - Orange color on hover
  • font-medium - Home link is slightly bolder (emphasis)

Complete Header Component Code

Here's our complete Header component:

"use client";

import { ShoppingCart, Search, Menu, User, Heart } from "lucide-react";
import { Input } from "./ui/input";
import { Button } from "./ui/button";

export default function Header() {
  return (
    <header className="sticky top-0 z-50 bg-white border-b shadow-sm">
      {/* Top Banner */}
      <div className="bg-gradient-to-r from-orange-500 to-pink-500 text-white text-center py-2 text-sm font-medium">
        🎉 Free shipping on orders over $29 • Shop now and save big!
      </div>

      {/* Main Header */}
      <div className="container mx-auto px-4 py-3">
        <div className="flex items-center justify-between gap-4">
          {/* Logo */}
          <div className="flex items-center gap-2">
            <Button variant="ghost" size="icon" className="lg:hidden">
              <Menu className="h-6 w-6" />
            </Button>
            <a href="/" className="text-2xl font-bold text-orange-500">
              Temu
            </a>
          </div>

          {/* Search Bar */}
          <div className="flex-1 max-w-2xl relative">
            <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" />
            <Input
              type="text"
              placeholder="Search for products..."
              className="pl-10 pr-4 py-5 w-full rounded-full border-2 border-gray-200 focus:border-orange-500"
            />
          </div>

          {/* Right Actions */}
          <div className="flex items-center gap-2">
            <Button variant="ghost" size="icon" className="relative">
              <Heart className="h-6 w-6" />
            </Button>
            <Button variant="ghost" size="icon" className="relative">
              <ShoppingCart className="h-6 w-6" />
              <span className="absolute -top-1 -right-1 bg-orange-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
                0
              </span>
            </Button>
            <Button variant="ghost" size="icon">
              <User className="h-6 w-6" />
            </Button>
          </div>
        </div>

        {/* Navigation Menu */}
        <nav className="hidden lg:flex items-center gap-6 mt-4 text-sm">
          <a href="#" className="hover:text-orange-500 font-medium">
            Home
          </a>
          <a href="#" className="hover:text-orange-500">
            Flash Sale
          </a>
          <a href="#" className="hover:text-orange-500">
            Electronics
          </a>
          <a href="#" className="hover:text-orange-500">
            Fashion
          </a>
          <a href="#" className="hover:text-orange-500">
            Home & Garden
          </a>
          <a href="#" className="hover:text-orange-500">
            Sports
          </a>
          <a href="#" className="hover:text-orange-500">
            Toys & Games
          </a>
          <a href="#" className="hover:text-orange-500">
            Beauty
          </a>
        </nav>
      </div>
    </header>
  );
}

Part 4: Building the Product Card Component

Product cards are essential for e-commerce sites. Let's create a reusable ProductCard component.

Create components/ProductCard.tsx:

"use client";

import Image from "next/image";
import { Card, CardContent } from "./ui/card";
import { Badge } from "./ui/badge";
import { Heart, Star } from "lucide-react";
import { Button } from "./ui/button";

interface ProductCardProps {
  id: number;
  title: string;
  image: string;
  price: number;
  originalPrice: number;
  rating: number;
  reviews: number;
  discount: number;
  sold: number;
}

export default function ProductCard({
  title,
  image,
  price,
  originalPrice,
  rating,
  reviews,
  discount,
  sold,
}: ProductCardProps) {
  return (
    <Card className="group overflow-hidden cursor-pointer hover:shadow-lg transition-all duration-300 border-gray-200">
      <CardContent className="p-0">
        {/* Image Container */}
        <div className="relative aspect-square overflow-hidden bg-gray-100">
          <Image
            src={image}
            alt={title}
            fill
            className="object-cover group-hover:scale-105 transition-transform duration-300"
          />
          {discount > 0 && (
            <Badge className="absolute top-2 left-2 bg-red-500 hover:bg-red-600">
              -{discount}%
            </Badge>
          )}
          <Button
            variant="ghost"
            size="icon"
            className="absolute top-2 right-2 bg-white/80 hover:bg-white"
          >
            <Heart className="h-4 w-4" />
          </Button>
        </div>

        {/* Product Info */}
        <div className="p-3 space-y-2">
          <h3 className="text-sm font-medium line-clamp-2 min-h-[40px]">
            {title}
          </h3>

          {/* Price */}
          <div className="flex items-baseline gap-2">
            <span className="text-xl font-bold text-orange-500">
              ${price.toFixed(2)}
            </span>
            <span className="text-sm text-gray-400 line-through">
              ${originalPrice.toFixed(2)}
            </span>
          </div>

          {/* Rating and Sold */}
          <div className="flex items-center justify-between text-xs text-gray-600">
            <div className="flex items-center gap-1">
              <Star className="h-3 w-3 fill-yellow-400 text-yellow-400" />
              <span className="font-medium">{rating.toFixed(1)}</span>
              <span>({reviews})</span>
            </div>
            <span>{sold}+ sold</span>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

Key Features:

  • TypeScript Interface: Defines the props structure
  • Next.js Image: Optimized image loading with fill prop
  • Hover Effects: Image scales on hover using group and group-hover
  • Discount Badge: Shows discount percentage
  • Rating Display: Star icon with rating number
  • Price Comparison: Shows both sale and original price

Part 5: Building the Category Card Component

Category cards help users navigate product categories quickly.

Create components/CategoryCard.tsx:

import Image from "next/image";

interface CategoryCardProps {
  name: string;
  image: string;
  icon: string;
}

export default function CategoryCard({ name, image, icon }: CategoryCardProps) {
  return (
    <div className="flex flex-col items-center gap-2 cursor-pointer group">
      <div className="w-20 h-20 rounded-full bg-gradient-to-br from-orange-100 to-pink-100 flex items-center justify-center overflow-hidden group-hover:shadow-md transition-all duration-300 border-2 border-transparent group-hover:border-orange-300">
        <span className="text-3xl">{icon}</span>
      </div>
      <span className="text-xs text-center font-medium text-gray-700 group-hover:text-orange-500">
        {name}
      </span>
    </div>
  );
}

Key Features:

  • Simple, clean design with emoji icons
  • Circular container with gradient background
  • Hover effects for interactivity
  • Perfect for grid layouts

Part 6: Building the Hero Carousel Component

The hero carousel showcases promotional content at the top of the page.

Create components/HeroCarousel.tsx:

"use client";

import * as React from "react";
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "./ui/carousel";
import Autoplay from "embla-carousel-autoplay";

export default function HeroCarousel() {
  const plugin = React.useRef(
    Autoplay({ delay: 4000, stopOnInteraction: true })
  );

  const slides = [
    {
      id: 1,
      title: "Super Deals",
      subtitle: "Up to 90% OFF",
      color: "from-orange-400 to-pink-500",
    },
    {
      id: 2,
      title: "New Arrivals",
      subtitle: "Shop the Latest Trends",
      color: "from-purple-400 to-blue-500",
    },
    {
      id: 3,
      title: "Flash Sale",
      subtitle: "Limited Time Offers",
      color: "from-green-400 to-teal-500",
    },
  ];

  return (
    <Carousel
      plugins={[plugin.current]}
      className="w-full"
      onMouseEnter={plugin.current.stop}
      onMouseLeave={plugin.current.reset}
    >
      <CarouselContent>
        {slides.map((slide) => (
          <CarouselItem key={slide.id}>
            <div
              className={`relative h-[300px] md:h-[400px] rounded-xl overflow-hidden bg-gradient-to-r ${slide.color}`}
            >
              <div className="container mx-auto h-full flex items-center px-8">
                <div className="text-white">
                  <h2 className="text-4xl md:text-6xl font-bold mb-4">
                    {slide.title}
                  </h2>
                  <p className="text-xl md:text-2xl mb-6">{slide.subtitle}</p>
                  <button className="bg-white text-gray-900 px-8 py-3 rounded-full font-semibold hover:bg-gray-100 transition-colors">
                    Shop Now
                  </button>
                </div>
              </div>
            </div>
          </CarouselItem>
        ))}
      </CarouselContent>
      <CarouselPrevious className="left-4" />
      <CarouselNext className="right-4" />
    </Carousel>
  );
}

Key Features:

  • Autoplay: Slides automatically change every 4 seconds
  • Pause on Hover: Stops autoplay when user hovers
  • Navigation Arrows: Previous/Next buttons
  • Gradient Backgrounds: Eye-catching colorful slides
  • Responsive Heights: Adapts to screen size

Part 7: Building the Footer Component

Every website needs a professional footer with links and information.

Create components/Footer.tsx:

import { Facebook, Instagram, Twitter, Youtube } from "lucide-react";
import { Separator } from "./ui/separator";

export default function Footer() {
  return (
    <footer className="bg-gray-50 border-t mt-16">
      <div className="container mx-auto px-4 py-12">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
          {/* Company Info */}
          <div>
            <h3 className="text-2xl font-bold text-orange-500 mb-4">Temu</h3>
            <p className="text-sm text-gray-600 mb-4">
              Your one-stop shop for everything you need at unbeatable prices.
            </p>
            <div className="flex gap-3">
              <a
                href="#"
                className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center hover:bg-orange-500 hover:text-white transition-colors"
              >
                <Facebook className="h-4 w-4" />
              </a>
              <a
                href="#"
                className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center hover:bg-orange-500 hover:text-white transition-colors"
              >
                <Instagram className="h-4 w-4" />
              </a>
              <a
                href="#"
                className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center hover:bg-orange-500 hover:text-white transition-colors"
              >
                <Twitter className="h-4 w-4" />
              </a>
              <a
                href="#"
                className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center hover:bg-orange-500 hover:text-white transition-colors"
              >
                <Youtube className="h-4 w-4" />
              </a>
            </div>
          </div>

          {/* Customer Service */}
          <div>
            <h4 className="font-semibold mb-4">Customer Service</h4>
            <ul className="space-y-2 text-sm text-gray-600">
              <li>
                <a href="#" className="hover:text-orange-500">
                  Help Center
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Track Order
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Returns & Refunds
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Shipping Info
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Contact Us
                </a>
              </li>
            </ul>
          </div>

          {/* Shop */}
          <div>
            <h4 className="font-semibold mb-4">Shop</h4>
            <ul className="space-y-2 text-sm text-gray-600">
              <li>
                <a href="#" className="hover:text-orange-500">
                  Flash Sales
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  New Arrivals
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Best Sellers
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Clearance
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Gift Cards
                </a>
              </li>
            </ul>
          </div>

          {/* About */}
          <div>
            <h4 className="font-semibold mb-4">About</h4>
            <ul className="space-y-2 text-sm text-gray-600">
              <li>
                <a href="#" className="hover:text-orange-500">
                  About Us
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Careers
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Privacy Policy
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Terms of Service
                </a>
              </li>
              <li>
                <a href="#" className="hover:text-orange-500">
                  Blog
                </a>
              </li>
            </ul>
          </div>
        </div>

        <Separator className="my-8" />

        <div className="text-center text-sm text-gray-600">
          <p>
            © 2024 Temu Clone. All rights reserved. This is for educational
            purposes only.
          </p>
        </div>
      </div>
    </footer>
  );
}

Key Features:

  • 4-Column Layout: Responsive grid that adapts to screen size
  • Social Media Icons: Clickable icons with hover effects
  • Link Sections: Organized navigation for different areas
  • Copyright Notice: Legal information at the bottom

Part 8: Building the Main Homepage

Now let's put everything together in the main page!

Update app/page.tsx with this complete code:

import Header from "@/components/Header";
import Footer from "@/components/Footer";
import HeroCarousel from "@/components/HeroCarousel";
import CategoryCard from "@/components/CategoryCard";
import ProductCard from "@/components/ProductCard";
import { Separator } from "@/components/ui/separator";

// Sample product data
const products = [
  {
    id: 1,
    title: "Wireless Bluetooth Earbuds with Charging Case - HD Sound Quality",
    image:
      "https://images.unsplash.com/photo-1590658268037-6bf12165a8df?w=400&h=400&fit=crop",
    price: 12.99,
    originalPrice: 49.99,
    rating: 4.8,
    reviews: 2341,
    discount: 74,
    sold: 15000,
  },
  {
    id: 2,
    title: "Smart Watch Fitness Tracker with Heart Rate Monitor",
    image:
      "https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=400&h=400&fit=crop",
    price: 19.99,
    originalPrice: 89.99,
    rating: 4.6,
    reviews: 1823,
    discount: 78,
    sold: 12000,
  },
  {
    id: 3,
    title: "LED Desk Lamp with USB Charging Port - Adjustable Brightness",
    image:
      "https://images.unsplash.com/photo-1507473885765-e6ed057f782c?w=400&h=400&fit=crop",
    price: 15.49,
    originalPrice: 59.99,
    rating: 4.7,
    reviews: 956,
    discount: 74,
    sold: 8500,
  },
  {
    id: 4,
    title: "Portable Phone Stand Holder - Universal Adjustable Desktop Mount",
    image:
      "https://images.unsplash.com/photo-1556656793-08538906a9f8?w=400&h=400&fit=crop",
    price: 7.99,
    originalPrice: 24.99,
    rating: 4.5,
    reviews: 3421,
    discount: 68,
    sold: 25000,
  },
  {
    id: 5,
    title: "Stainless Steel Water Bottle - Insulated 32oz",
    image:
      "https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=400&h=400&fit=crop",
    price: 14.99,
    originalPrice: 39.99,
    rating: 4.9,
    reviews: 1234,
    discount: 63,
    sold: 9800,
  },
  {
    id: 6,
    title: "Wireless Keyboard and Mouse Combo - Ultra Slim Design",
    image:
      "https://images.unsplash.com/photo-1587829741301-dc798b83add3?w=400&h=400&fit=crop",
    price: 22.99,
    originalPrice: 79.99,
    rating: 4.6,
    reviews: 876,
    discount: 71,
    sold: 6700,
  },
  {
    id: 7,
    title: "HD Webcam 1080p with Microphone - Perfect for Video Calls",
    image:
      "https://images.unsplash.com/photo-1585792180666-f7347c490ee2?w=400&h=400&fit=crop",
    price: 18.99,
    originalPrice: 69.99,
    rating: 4.4,
    reviews: 1567,
    discount: 73,
    sold: 11200,
  },
  {
    id: 8,
    title: "Car Phone Mount - Dashboard Windshield Holder",
    image:
      "https://images.unsplash.com/photo-1526738549149-8e07eca6c147?w=400&h=400&fit=crop",
    price: 9.99,
    originalPrice: 29.99,
    rating: 4.7,
    reviews: 2890,
    discount: 67,
    sold: 18500,
  },
];

const categories = [
  { name: "Electronics", icon: "📱", image: "" },
  { name: "Fashion", icon: "👗", image: "" },
  { name: "Home", icon: "🏠", image: "" },
  { name: "Beauty", icon: "💄", image: "" },
  { name: "Sports", icon: "⚽", image: "" },
  { name: "Toys", icon: "🧸", image: "" },
  { name: "Books", icon: "📚", image: "" },
  { name: "Garden", icon: "🌱", image: "" },
  { name: "Pets", icon: "🐾", image: "" },
  { name: "Automotive", icon: "🚗", image: "" },
];

export default function Home() {
  return (
    <div className="min-h-screen bg-gray-50">
      <Header />

      <main>
        {/* Hero Section */}
        <section className="container mx-auto px-4 py-6">
          <HeroCarousel />
        </section>

        {/* Categories Section */}
        <section className="container mx-auto px-4 py-8">
          <h2 className="text-2xl font-bold mb-6">Shop by Category</h2>
          <div className="grid grid-cols-5 md:grid-cols-10 gap-4">
            {categories.map((category) => (
              <CategoryCard
                key={category.name}
                name={category.name}
                icon={category.icon}
                image={category.image}
              />
            ))}
          </div>
        </section>

        <Separator className="my-8" />

        {/* Flash Sale Section */}
        <section className="container mx-auto px-4 py-8">
          <div className="flex items-center justify-between mb-6">
            <div>
              <h2 className="text-2xl font-bold">⚡ Flash Sale</h2>
              <p className="text-gray-600 text-sm">
                Limited time offers - Don't miss out!
              </p>
            </div>
            <a href="#" className="text-orange-500 font-medium hover:underline">
              View All →
            </a>
          </div>

          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
            {products.slice(0, 5).map((product) => (
              <ProductCard key={product.id} {...product} />
            ))}
          </div>
        </section>

        <Separator className="my-8" />

        {/* New Arrivals Section */}
        <section className="container mx-auto px-4 py-8">
          <div className="flex items-center justify-between mb-6">
            <div>
              <h2 className="text-2xl font-bold">🆕 New Arrivals</h2>
              <p className="text-gray-600 text-sm">
                Check out the latest products
              </p>
            </div>
            <a href="#" className="text-orange-500 font-medium hover:underline">
              View All →
            </a>
          </div>

          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
            {products.map((product) => (
              <ProductCard key={product.id} {...product} />
            ))}
          </div>
        </section>

        {/* Popular Products Section */}
        <section className="container mx-auto px-4 py-8">
          <div className="flex items-center justify-between mb-6">
            <div>
              <h2 className="text-2xl font-bold">🔥 Popular Products</h2>
              <p className="text-gray-600 text-sm">Most loved by customers</p>
            </div>
            <a href="#" className="text-orange-500 font-medium hover:underline">
              View All →
            </a>
          </div>

          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
            {products.slice(0, 5).map((product) => (
              <ProductCard key={product.id} {...product} />
            ))}
          </div>
        </section>
      </main>

      <Footer />
    </div>
  );
}

Understanding the Homepage Structure:

  1. Product Data Array: We define 8 sample products with all their details
  2. Category Data Array: 10 categories with emoji icons
  3. Layout Sections:
    • Hero carousel at the top
    • Category grid
    • Flash Sale section (first 5 products)
    • New Arrivals section (all 8 products)
    • Popular Products section (first 5 products)
  4. Responsive Grids: Different column counts for mobile, tablet, and desktop
  5. Separator Components: Visual dividers between sections

Part 9: Updating the Layout

Let's update the metadata in app/layout.tsx:

export const metadata: Metadata = {
  title: "Temu Clone - Shop for Everything at Unbeatable Prices",
  description:
    "Educational Temu clone built with Next.js, Tailwind CSS, and Shadcn UI. Explore amazing deals on electronics, fashion, home goods, and more.",
};

This improves SEO and gives your site a professional title and description.


What We've Built

In this comprehensive tutorial, we've built a complete e-commerce website! Here's everything we covered:

Project Setup - Created a Next.js 16 app with TypeScript and Tailwind CSS
Shadcn UI Integration - Installed and configured Shadcn UI components
Header Component - Sticky navigation with search, cart, and user icons
Product Cards - Reusable cards with images, ratings, and prices
Category Cards - Icon-based category navigation
Hero Carousel - Auto-playing promotional slides
Footer Component - Professional footer with links and social media
Homepage Layout - Complete page with multiple product sections
TypeScript Interfaces - Type-safe component props
Responsive Design - Mobile-first approach with Tailwind breakpoints
Component Composition - Building complex UIs from simple components


Testing Your Application

Now let's see your complete website in action! In your terminal, run:

npm run dev

Open your browser and navigate to http://localhost:3000

You should see:

  • ✅ Sticky header with search bar and icons
  • ✅ Auto-playing hero carousel
  • ✅ Category icons in a grid
  • ✅ Flash Sale products
  • ✅ New Arrivals section
  • ✅ Popular Products section
  • ✅ Professional footer at the bottom

Try these interactions:

  • Hover over product cards to see the zoom effect
  • Watch the carousel auto-play
  • Hover over the carousel to pause it
  • Try resizing your browser to see responsive design in action

Complete Project Structure

Your project should now have this structure:

temu-web/
├── app/
│   ├── layout.tsx           # Root layout with metadata
│   ├── page.tsx             # Homepage with all sections
│   └── globals.css          # Global styles
├── components/
│   ├── ui/                  # Shadcn UI components
│   │   ├── button.tsx
│   │   ├── card.tsx
│   │   ├── input.tsx
│   │   ├── badge.tsx
│   │   ├── carousel.tsx
│   │   ├── separator.tsx
│   │   └── avatar.tsx
│   ├── Header.tsx           # Navigation header
│   ├── Footer.tsx           # Footer component
│   ├── HeroCarousel.tsx     # Hero carousel
│   ├── ProductCard.tsx      # Product display card
│   └── CategoryCard.tsx     # Category icon card
├── lib/
│   └── utils.ts             # Utility functions
├── components.json          # Shadcn config
├── package.json             # Dependencies
└── tsconfig.json            # TypeScript config

Key Concepts Learned

1. Component Architecture

You learned how to break down a complex UI into smaller, reusable components. Each component has a single responsibility.

2. TypeScript for Type Safety

Using interfaces ensures your components receive the correct props and catches errors at compile time.

3. Tailwind CSS Utilities

Instead of writing custom CSS, we used utility classes for rapid development:

  • flex, grid for layouts
  • hover:, md:, lg: for responsive states
  • bg-, text-, border- for styling

4. Shadcn UI Benefits

Pre-built, accessible components that we can customize with Tailwind classes. No need to build from scratch!

5. Next.js Features

  • App Router: Modern routing system
  • Image Optimization: Automatic image optimization
  • TypeScript Support: Built-in TypeScript configuration
  • Server & Client Components: Optimized rendering

Responsive Behavior

Your website is fully responsive across all devices:

Mobile (< 768px):

  • 2-column product grid
  • Hamburger menu icon visible
  • 5-column category grid
  • Stacked footer columns

Tablet (768px - 1023px):

  • 3-column product grid
  • 10-column category grid
  • 2-column footer

Desktop (≥ 1024px):

  • 4-5 column product grid
  • Full navigation menu visible
  • 4-column footer

Next Steps & Enhancements

Now that you have a complete Temu clone, here are some ideas to extend your learning:

Beginner Level:

  • Change the color scheme (replace orange with your brand color)
  • Add more products to the arrays
  • Modify the promotional banner text
  • Add more category icons

Intermediate Level:

  • Create a product detail page with dynamic routing
  • Add a shopping cart with React Context
  • Implement product filtering by category
  • Add a dark mode toggle

Advanced Level:

  • Connect to a CMS like Contentful or Sanity
  • Add authentication with NextAuth.js
  • Implement real-time search
  • Add animations with Framer Motion
  • Deploy to Vercel

Key Takeaways

  1. Next.js is powerful - Built-in features like routing, image optimization, and TypeScript support make development fast
  2. Component reusability - Building small, focused components makes your code maintainable
  3. Tailwind CSS speeds development - Utility classes are faster than writing custom CSS
  4. Shadcn UI saves time - High-quality components that you can customize
  5. TypeScript prevents bugs - Type checking catches errors before runtime
  6. Responsive design is essential - Always design for mobile first
  7. Code organization matters - Clean folder structure makes projects scalable

Common Issues & Troubleshooting

Issue: "Module not found" errors

Solution: Make sure all dependencies are installed:

npm install

Issue: Shadcn components not found

Solution: Re-add the components:

npx shadcn@latest add button card input badge carousel separator avatar

Issue: Images not loading

Solution: The images use Unsplash URLs. Make sure you're connected to the internet. Alternatively, replace with local images in the /public folder.

Issue: Carousel not auto-playing

Solution: Ensure embla-carousel-autoplay is installed:

npm install embla-carousel-autoplay

Issue: Tailwind styles not applying

Solution: Clear the Next.js cache and restart:

rm -rf .next
npm run dev

Issue: TypeScript errors

Solution: Make sure all component files have the correct interfaces and imports. Check that you're using the exact code from this tutorial.


Challenge Exercises

Now that you have a complete project, try these challenges to reinforce your learning:

Easy Challenges:

  1. Change the brand color from orange to blue throughout the site
  2. Add 5 more products to the product array
  3. Modify the promotional banner message
  4. Add 3 more categories with different emoji icons
  5. Change the footer copyright year to 2025

Medium Challenges:

  1. Create a "Deal of the Day" section with a countdown timer
  2. Add a "Back to Top" button that appears when scrolling
  3. Implement a simple product search (filter by title)
  4. Add more carousel slides with different colors
  5. Create a mobile sidebar menu (drawer)

Hard Challenges:

  1. Add page routing - create an About page and Products page
  2. Implement a shopping cart using React Context
  3. Add a wishlist feature that stores items in localStorage
  4. Create product detail pages with dynamic routing
  5. Add animations to components using Framer Motion

Performance Tips

Your application is already optimized, but here are some best practices we followed:

Next.js Image Component: Automatically optimizes images
Server Components: Used where possible for better performance
Code Splitting: Each component is imported separately
Lazy Loading: Images load as they come into view
Minimal JavaScript: Only client components where needed


Deployment

Ready to share your project with the world? Deploy to Vercel (free):

  1. Push to GitHub:
git init
git add .
git commit -m "Complete Temu clone"
git branch -M main
git remote add origin YOUR_GITHUB_URL
git push -u origin main
  1. Deploy to Vercel:
  • Go to vercel.com
  • Click "New Project"
  • Import your GitHub repository
  • Click "Deploy"

Your site will be live in minutes!


Additional Resources

Official Documentation:


What's Next?

Congratulations! 🎉 You've successfully built a complete, production-ready e-commerce website from scratch!

You now have:

  • ✅ A fully functional Temu clone
  • ✅ Understanding of Next.js App Router
  • ✅ Skills in Tailwind CSS and responsive design
  • ✅ Knowledge of Shadcn UI components
  • ✅ Experience with TypeScript interfaces
  • ✅ A portfolio project to showcase

Future Tutorial Ideas:

In future parts of this series, we could cover:

  • Part 2: Adding product detail pages with dynamic routing
  • Part 3: Building a shopping cart with React Context
  • Part 4: User authentication and profile pages
  • Part 5: Connecting to a backend API
  • Part 6: Admin dashboard for managing products
  • Part 7: Payment integration (Stripe)
  • Part 8: Order tracking and user history

Final Thoughts

Building real-world projects is the best way to learn web development. You didn't just follow a tutorial - you built a complete, modern e-commerce website using professional tools and best practices.

The skills you learned here are:

  • ✅ Directly applicable to real jobs
  • ✅ Used by companies worldwide
  • ✅ Modern and up-to-date
  • ✅ Scalable for larger projects

Keep building, keep learning, and most importantly, keep coding!


Get Help

If you run into any issues:

  1. Check the error message - Read it carefully, it usually tells you what's wrong
  2. Review the code - Compare your code with the tutorial
  3. Check the documentation - Links provided above
  4. Search online - Google the error message
  5. Ask the community - Discord, Reddit, Stack Overflow

Remember: Every developer gets stuck. It's part of the learning process!


Share Your Project

Built something awesome? Share it!

  • Tweet about it with #NextJS #TailwindCSS
  • Share on LinkedIn
  • Post in coding communities
  • Add it to your portfolio
  • Show it in job interviews

Congratulations on completing this tutorial! 🎉

You've learned Next.js, Tailwind CSS, Shadcn UI, and TypeScript by building a real-world project. These are valuable, in-demand skills that will serve you well in your development career.

Keep building amazing things!


Happy coding! 🚀

029

Comments (0)

Sign in to join the conversation