All components

Customer Reviews

Customer Reviews is a React and Tailwind CSS component from Bund UI, licensed MIT. Copy it and paste it into your project.

Bund UI MIT other

What it is

Customer Reviews is a React and Tailwind CSS component from Bund UI, licensed MIT. Copy it and paste it into your project.

How to use it

Open it in the catalogue, press copy, and paste it into your project. The prompt you copy carries the code and the rules that tell your agent to reproduce it without changing anything.

Open in the catalogue

Five free copies a month. No card.

Needs

npm i lucide-react

Licence

This component comes from Bund UI and is redistributed under the MIT licence, which permits commercial use. The copyright notice travels with the code.

Customer Reviews

examples/blocks/ecommerce/customer-reviews/01/data.ts
export const reviews = [
  {
    id: 1,
    customerName: "Sarah Johnson",
    customerAvatar:
      "https://plus.unsplash.com/premium_photo-1671656349218-5218444643d8?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&q=80&w=200",
    rating: 5,
    reviewDate: "2 week ago",
    totalSpend: 450,
    totalReviews: 8,
    reviewText:
      "Absolutely love this product! The quality exceeded my expectations and the customer service was outstanding. I've been a loyal customer for over a year now and have never been disappointed. Highly recommend to anyone looking for premium quality."
  },
  {
    id: 2,
    customerName: "Michael Chen",
    customerAvatar:
      "https://images.unsplash.com/photo-1701615004837-40d8573b6652?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTl8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
    rating: 4,
    reviewDate: "Yesterday",
    totalSpend: 680,
    totalReviews: 12,
    reviewText:
      "Great experience overall! The product arrived quickly and was exactly as described. The attention to detail is impressive. Only giving 4 stars because I wish there were more color options available, but that's a minor issue."
  },
  {
    id: 3,
    customerName: "Emma Davis",
    customerAvatar:
      "https://plus.unsplash.com/premium_photo-1689551670902-19b441a6afde?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MjV8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
    rating: 5,
    reviewDate: "1 week ago",
    totalSpend: 320,
    totalReviews: 6,
    reviewText:
      "This is my third purchase and I keep coming back because the quality is consistently excellent. The packaging is beautiful and the product itself is even better in person. Will definitely be ordering again!"
  },
  {
    id: 4,
    customerName: "James Wilson",
    customerAvatar:
      "https://images.unsplash.com/photo-1623582854588-d60de57fa33f?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MjJ8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
    rating: 5,
    reviewDate: "4 days ago",
    totalSpend: 890,
    totalReviews: 15,
    reviewText:
      "Outstanding quality and craftsmanship! I've recommended this to all my friends and family. The value for money is incredible and the customer support team went above and beyond to ensure I was satisfied with my purchase."
  }
];
examples/blocks/ecommerce/customer-reviews/01/page.tsx
import { ReviewCard } from "./review-card";
import { reviews } from "./data";

export default function CustomerReviews() {
  const averageRating = (
    reviews.reduce((acc, review) => acc + review.rating, 0) / reviews.length
  ).toFixed(1);

  const totalReviews = reviews.length;

  return (
    <section className="py-10 lg:py-20">
      <div className="mx-auto max-w-3xl px-4">
        <header className="mb-6 flex flex-col justify-between border-b pb-4 lg:mb-10 lg:flex-row lg:pb-6">
          <h1 className="text-foreground font-heading text-xl md:text-2xl">Customer Reviews</h1>
          <div className="text-muted-foreground flex items-center gap-2 lg:items-end lg:justify-center">
            <div className="flex items-center gap-2 lg:items-end">
              <span className="text-lg font-bold text-amber-500 md:text-2xl">{averageRating}</span>
              <span className="text-sm">out of 5</span>
            </div>
            <span>•</span>
            <span className="text-sm">based on {totalReviews} reviews</span>
          </div>
        </header>

        <div className="grid gap-6 divide-y lg:grid-cols-1 lg:gap-10 [&>div]:pb-6 lg:[&>div]:pb-10">
          {reviews.map((review, i) => (
            <ReviewCard key={i} review={review} />
          ))}
        </div>
      </div>
    </section>
  );
}
examples/blocks/ecommerce/customer-reviews/01/review-card.tsx
import { Star, ThumbsUp, ThumbsDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group";

interface ReviewCardProps {
  customerName: string;
  customerAvatar?: string;
  rating: number;
  reviewDate: string;
  totalSpend: number;
  totalReviews: number;
  reviewText: string;
}

export const ReviewCard = ({ review }: { review: ReviewCardProps }) => {
  const renderStars = () => {
    return Array(5)
      .fill("")
      .map((_, i) =>
        i < review.rating ? (
          <Star key={i} className="size-4 fill-amber-500 text-amber-500 lg:size-5" />
        ) : (
          <Star key={i} className="text-muted-foreground size-4 lg:size-5" />
        )
      );
  };

  return (
    <div className="flex gap-4">
      <Avatar className="size-12 rounded-none lg:size-20">
        <AvatarImage
          src={review.customerAvatar}
          alt={review.customerName}
          className="object-cover"
        />
      </Avatar>

      {/* Content */}
      <div className="min-w-0 flex-1">
        {/* Header */}
        <div className="mb-3 flex items-start justify-between gap-4">
          <div>
            <h3 className="mb-1 font-semibold">{review.customerName}</h3>
            <div className="text-muted-foreground flex gap-1 text-sm">
              Total Spend: <span className="font-semibold">${review.totalSpend}</span>
            </div>
          </div>
          <div className="flex flex-col items-end gap-2">
            <div className="flex items-center gap-1">{renderStars()}</div>
            <span className="text-muted-foreground text-sm whitespace-nowrap">
              {review.reviewDate}
            </span>
          </div>
        </div>

        {/* Review Text */}
        <p className="text-muted-foreground mb-4 leading-relaxed">{review.reviewText}</p>

        {/* Actions */}
        <div className="flex items-center gap-3">
          <ButtonGroup>
            <Button variant="secondary" size="sm">
              <ThumbsUp />
            </Button>
            <ButtonGroupSeparator />
            <Button variant="outline" size="icon-sm" disabled>
              15
            </Button>
          </ButtonGroup>
          <ButtonGroup>
            <Button variant="secondary" size="sm">
              <ThumbsDown />
            </Button>
            <ButtonGroupSeparator />
            <Button variant="outline" size="icon-sm" disabled>
              2
            </Button>
          </ButtonGroup>
        </div>
      </div>
    </div>
  );
};

Similar components