# Product Card

Product card in grid, list-row and hero layouts. Adding to the bag can send a small copy of the photo flying to your basket, quick-add turns into a quantity stepper, and saving fills the heart.

> Composed · Pro · Data Display — React Native, Expo Go compatible.

## Install

```bash
npx @lumioui/cli add pro/product-card
```

## Import

```tsx
import { ProductCard } from "@/components/ui/product-card/product-card";
```

## Variants

- `grid` — Catalogue grid: `npx @lumioui/cli add pro/product-card-grid`
- `hero` — Featured hero: `npx @lumioui/cli add pro/product-card-hero`
- `row` — Menu row: `npx @lumioui/cli add pro/product-card-row`

## Props

| Prop | Type | Notes |
| --- | --- | --- |
| `layout?` | `"grid" | "row" | "hero"` | Shape. Default "grid". |
| `image` | `string` | Product photo URL. |
| `imageAspect?` | `number` | Photo width/height ratio. Default 4/5 grid · 1 row · 4/3 hero. |
| `title` | `string` | Product name. |
| `brand?` | `string` | Brand / maker / restaurant line. |
| `description?` | `string` | One or two lines of description (row + hero). |
| `price` | `number` | Current price, major units. |
| `compareAt?` | `number` | Compare-at price — struck through when higher. |
| `unit?` | `string` | Unit for a unit price ("lb", "kg"). |
| `priceBadge?` | `PriceTagProps["badge"]` | Sale badge mode forwarded to PriceTag. Default "percent" when on sale. |
| `badge?` | `string` | Overlay pill on the photo — "New", "Bestseller", "Just in". |
| `rating?` | `number` | Average rating 0–5. |
| `reviewCount?` | `number` | Review count shown beside the rating. |
| `swatches?` | `string[]` | Colour dots under the title (grid). Any colour strings. |
| `maxSwatches?` | `number` | Max dots before "+N". Default 4. |
| `favorite?` | `boolean` | Controlled wishlist state. |
| `defaultFavorite?` | `boolean` | Uncontrolled initial wishlist state. Default false. |
| `onFavoriteChange?` | `(favorite: boolean) => void` | — |
| `showFavorite?` | `boolean` | Show the wishlist heart (grid + hero). Default true. |
| `quickAdd?` | `boolean` | Show the add control. Default true. |
| `quantity?` | `number` | Controlled bag quantity for the add control. |
| `defaultQuantity?` | `number` | Uncontrolled initial bag quantity. |
| `onQuantityChange?` | `(quantity: number) => void` | — |
| `addMode?` | `AddToCartButtonProps["mode"]` | Hero add-button behaviour. Default "confirm". |
| `addLabel?` | `string` | Hero add-button label. Default "Add to bag". |
| `onAdd?` | `() => void | Promise<unknown>` | Hero add handler (may be async — the button shows a spinner). |
| `soldOut?` | `boolean` | Out of stock — dims the photo, swaps the add control for "Sold out". |
| `onPress?` | `(e: GestureResponderEvent) => void` | Opens the product. |
| `format?` | `FormatPriceOptions` | Money formatting. |
| `flyTo?` | `React.RefObject<View | null>` | Where an add flies to — the basket bar or bag count. |
| `onAddLanded?` | `() => void` | Fires when the flying photo lands in `flyTo` (or at the commit without one). |
| `bagChip?` | `boolean` | Show the "n in bag" chip on the photo while the product is in the bag. Default true. |
| `className?` | `string` | — |

## Icons rendered

- `star` — /icons.html?i=star
- `heart` — /icons.html?i=heart

Source: https://lumioui.com/components/product-card