Product Card
E-commerce product card with ratings, pricing, wishlist, and cart functionality.
ReactTailwind CSSTypeScriptResponsiveCard
Live Preview
Interactive
Product Card.tsxLive Code
"use client";
import { useState } from "react";
interface Product {
id: string;
name: string;
price: number;
originalPrice?: number;
image: string;
category: string;
rating: number;
reviews: number;
badge?: string;
inStock: boolean;
}
export default function ProductCard() {
const [isLiked, setIsLiked] = useState(false);
const [isAddedToCart, setIsAddedToCart] = useState(false);
const product: Product = {
id: "1",
name: "Wireless Headphones",
price: 99.99,
originalPrice: 149.99,
image:
"https:\/\/images.unsplash.com\/photo-1505740420928-5e560c06d30e?w=400&h=300&fit=crop",
category: "Electronics",
rating: 4.5,
reviews: 128,
badge: "Sale",
inStock: true,
};
const handleAddToCart = () => {
setIsAddedToCart(true);
setTimeout(() => setIsAddedToCart(false), 2000);
};
const renderStars = (rating: number) => {
return (
<div className="flex items-center gap-1">
{[1, 2, 3, 4, 5].map((star) => (
<svg
key={star}
className={`w-4 h-4 ${
star <= rating ? "text-yellow-400" : "text-gray-300"
}`}
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" \/>
<\/svg>
))}
<\/div>
);
};
return (
<div className="flex items-center justify-center bg-gray-50 p-4">
<div className="max-w-sm w-full bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden hover:shadow-lg transition-shadow duration-300">
{\/* Image Section *\/}
<div className="relative group">
<img
src={product.image}
alt={product.name}
className="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300"
\/>
{\/* Badge *\/}
{product.badge && (
<div
className={`absolute top-3 left-3 px-2 py-1 rounded-lg text-xs font-medium ${
product.badge === "Sale"
? "bg-red-500 text-white"
: "bg-green-500 text-white"
}`}
>
{product.badge}
<\/div>
)}
{\/* Like Button *\/}
<button
onClick={() => setIsLiked(!isLiked)}
className="absolute top-3 right-3 w-8 h-8 bg-white rounded-full flex items-center justify-center shadow-md hover:shadow-lg transition-shadow"
>
<svg
className={`w-4 h-4 ${
isLiked ? "text-red-500 fill-current" : "text-gray-400"
}`}
fill={isLiked ? "currentColor" : "none"}
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
\/>
<\/svg>
<\/button>
{\/* Stock Overlay *\/}
{!product.inStock && (
<div className="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<span className="text-white font-medium bg-gray-800 px-3 py-1 rounded-lg">
Out of Stock
<\/span>
<\/div>
)}
<\/div>
{\/* Content Section *\/}
<div className="p-4">
{\/* Category *\/}
<span className="text-xs text-blue-600 font-medium bg-blue-50 px-2 py-1 rounded-lg">
{product.category}
<\/span>
{\/* Product Name *\/}
<h3 className="mt-3 text-lg font-semibold text-gray-900">
{product.name}
<\/h3>
{\/* Rating *\/}
<div className="mt-2 flex items-center gap-2">
{renderStars(product.rating)}
<span className="text-sm text-gray-600">
{product.rating} ({product.reviews})
<\/span>
<\/div>
{\/* Price *\/}
<div className="mt-3 flex items-center gap-2">
<span className="text-xl font-bold text-gray-900">
${product.price}
<\/span>
{product.originalPrice && (
<span className="text-sm text-gray-500 line-through">
${product.originalPrice}
<\/span>
)}
{product.originalPrice && (
<span className="text-sm text-red-600 font-medium">
{Math.round((1 - product.price \/ product.originalPrice) * 100)}%
off
<\/span>
)}
<\/div>
{\/* Add to Cart Button *\/}
<button
onClick={handleAddToCart}
disabled={!product.inStock}
className={`mt-4 w-full py-2 px-4 rounded-lg font-medium transition-colors ${
product.inStock
? isAddedToCart
? "bg-green-600 text-white"
: "bg-blue-600 hover:bg-blue-700 text-white"
: "bg-gray-300 text-gray-500 cursor-not-allowed"
}`}
>
{isAddedToCart
? "Added to Cart!"
: product.inStock
? "Add to Cart"
: "Out of Stock"}
<\/button>
<\/div>
<\/div>
<\/div>
);
}
How to use
- 1. Copy the component code
- 2. Paste it into your React/Next.js project
- 3. Make sure you have Tailwind CSS configured
- 4. Customize colors, spacing, and content as needed
Dependencies
react
^18.0.0tailwindcss
^3.0.0Back to Components
Need complete templates?
View Premium Templates