labsUI

Product Card

Shop tile: photos in an AspectRatio (a swipeable Carousel with dots when there are several), sale price, Badge and add-to-cart Button.

npx @kznlabs/labsui add product-card
−20%

Clip camera

$349.00now $279.00

New

Studio headphones

$129.00

import { ProductCard } from "@/components/blocks/product-card";type Product = {  id: string;  name: string;  price: number;  compareAt?: number;  images: string[];};export function ProductGrid({  products,  onAdd,}: {  products: Product[];  onAdd: (id: string) => void;}) {  return (    <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">      {products.map((p) => (        <ProductCard          key={p.id}          name={p.name}          price={p.price}          compareAt={p.compareAt}          badge={p.compareAt ? "Sale" : undefined}          href={`/products/${p.id}`}          media={p.images.map((src) => (            <img key={src} src={src} alt="" />          ))}          onAddToCart={() => onAdd(p.id)}        />      ))}    </div>  );}

<ProductCard>

Shop tile: photos in an AspectRatio (a Carousel when there are several), name, price, badge, add button.

  • media*
    ReactNode[]

    Photos (<img>), one per slide. Several become a swipeable carousel with dots.

  • name*
    string

    Product name, the card's heading.

  • price*
    number

    Current price in major units, e.g. 49.99.

  • addLabeldefault "Add to cart"
    ReactNode

    Add button text.

  • badge
    string

    Small label over the media, e.g. "New".

  • compareAt
    number

    Struck-through original price for a sale.

  • currencydefault "USD"
    string

    ISO 4217 code for the price.

  • href
    string

    Product page link for the name.

  • localedefault "en-US"
    string

    BCP 47 locale for number formatting.

  • onAddToCart
    () => void

    Shows the add button; called when it is pressed.

  • ratiodefault 4 / 3
    number

    Media width/height, e.g. 1 for square.

PropTypeDefault
media*

Photos (<img>), one per slide. Several become a swipeable carousel with dots.

ReactNode[]—
name*

Product name, the card's heading.

string—
price*

Current price in major units, e.g. 49.99.

number—
addLabel

Add button text.

ReactNode"Add to cart"
badge

Small label over the media, e.g. "New".

string—
compareAt

Struck-through original price for a sale.

number—
currency

ISO 4217 code for the price.

string"USD"
href

Product page link for the name.

string—
locale

BCP 47 locale for number formatting.

string"en-US"
onAddToCart

Shows the add button; called when it is pressed.

() => void—
ratio

Media width/height, e.g. 1 for square.

number4 / 3

* required. Every component also takes className.