Product Card
betaA shop tile with image zoom, badge, half-star rating, discount pricing, a wishlist toggle and an add-to-cart confirmation.
- Display
- 1 file
- No extra npm packages
- Accessibility notes
pnpm dlx @dowel-ui/cli add product-cardNo npm packages are needed beyond what Dowel already requires.
import { ProductCard } from "@/components/ui/product-card";Default
Gallery
Wishlisted
Other Currency
With Extra Content
<ProductCard>
| Prop | Type | Default |
|---|---|---|
image (required)Image URL. | string | — |
price (required) | number | — |
title (required)Product name. Names the card, the cart button and the wishlist toggle. | string | — |
animateInPlays the entrance animation (tied to scrolling into view where supported). | boolean | true |
badgeA label over the image — "Sale", "New", "Limited". | ReactNode | — |
badgeVariantOverrides the badge colour chosen from its text. | BadgeProps["variant"] | — |
currencyISO 4217 code. | string | "USD" |
defaultWishlistedInitial wishlist state when uncontrolled. | boolean | false |
hrefMakes the title a link covering the whole card; the buttons stay on top of it. | string | — |
imageAltAlt text for the image. Empty by default: the title beside it already names the product. | string | "" |
localeLocale for number formatting. Defaults to the reader's. | string | — |
onAddToCartCalled when "Add to cart" is pressed. The button confirms and reverts on its own. | () => void | — |
onWishlistChange | (wishlisted: boolean) => void | — |
originalPriceA higher earlier price. Shows struck through, with the discount. | number | — |
rating0–5, shown to the nearest half star. | number | — |
wishlistedControlled wishlist state. | boolean | — |
childrenExtra content under the price, before the button. | ReactNode | — |
Plus every attribute of <article> except title.
8/8
checks passed
- Tested — passes
- axe assertion — passes
- Keyboard tested — does not apply
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — passes
- className merged — passes
- Visible focus — does not apply
- No fixed widths — passes