
Product Grid
Commerce
Search by name, tag, category or type
Source and install need .
pnpm dlx shadcn@latest add @assembli/product-detailA complete product page section built from Product Gallery and Variant Picker. The buying column sticks while photos scroll: breadcrumbs, rating, a price that follows the selection with savings and installments, a quantity stepper, add to cart that confirms in place and turns into Notify me when sold out, a wishlist heart, perks and expanding detail sections.
Other props pass through to the root element.
title*
string
eyebrow
React.ReactNode
A line above the title: the brand or collection.
breadcrumbs
{ label: string; href: string }[]
images*
GalleryImage[]
price*
number | ((selection: VariantSelection) => number)
Price for a selection; a number when it never changes.
compareAt
number | ((selection: VariantSelection) => number | undefined)
A struck-through original price for a selection.
installments
number
Split the price into this many interest-free payments under it.
currency
string
Default "USD"
locale
string
Default "en-US"
rating
{ value: number; count: number; href?: string }
description
React.ReactNode
options
VariantOption[]
Default []
defaultSelection
VariantSelection
stockOf
(selection: VariantSelection) => number | undefined
imageFor
(selection: VariantSelection, changed: string) => number | undefined
Gallery image to show when an option changes, e.g. jump to the photo of a color.
shipping
React.ReactNode
Shown beside "In stock".
perks
ProductPerk[]
sections
ProductSection[]
onAddToCart
(selection: VariantSelection, quantity: number) => void | Promise<unknown>
Return a promise to show "Adding…" until it settles.
onNotify
(selection: VariantSelection) => void
saved
boolean
Saved to a wishlist.
onSavedChange
(saved: boolean) => void
maxQuantity
number
Default 10
| Description | |||
|---|---|---|---|
| title* | string | – | |
| eyebrow | React.ReactNode | – | A line above the title: the brand or collection. |
| breadcrumbs | { label: string; href: string }[] | – | |
| images* | GalleryImage[] | – | |
| price* | number | ((selection: VariantSelection) => number) | – | Price for a selection; a number when it never changes. |
| compareAt | number | ((selection: VariantSelection) => number | undefined) | – | A struck-through original price for a selection. |
| installments | number | – | Split the price into this many interest-free payments under it. |
| currency | string | "USD" | |
| locale | string | "en-US" | |
| rating | { value: number; count: number; href?: string } | – | |
| description | React.ReactNode | – | |
| options | VariantOption[] | [] | |
| defaultSelection | VariantSelection | – | |
| stockOf | (selection: VariantSelection) => number | undefined | – | |
| imageFor | (selection: VariantSelection, changed: string) => number | undefined | – | Gallery image to show when an option changes, e.g. jump to the photo of a color. |
| shipping | React.ReactNode | – | Shown beside "In stock". |
| perks | ProductPerk[] | – | |
| sections | ProductSection[] | – | |
| onAddToCart | (selection: VariantSelection, quantity: number) => void | Promise<unknown> | – | Return a promise to show "Adding…" until it settles. |
| onNotify | (selection: VariantSelection) => void | – | |
| saved | boolean | – | Saved to a wishlist. |
| onSavedChange | (saved: boolean) => void | – | |
| maxQuantity | number | 10 |

Commerce

Commerce