CardProduct
The CardProduct component provides flexible product display with multiple variants (grid, carousel, list, cart, summary) tailored for various site layouts and functionalities.
Component
Storybook
Storybook - CardProduct DocumentationFigma Demo
Guidelines
Variations
CardProduct is offered in multiple variants tailored for various site layouts and functionalities. It includes:
- Grid: The default variant is the standard grid product card that appears in PLP/marketplace settings with grid view enabled. It includes pricing and cart widgets.
- Carousel: The carousel variant is intended for “discovery” settings such as carousels. It includes a primary CTA with no pricing or cart widgets.
- List: The default variant is the standard grid product card that appears in PLP/marketplace settings with list view enabled. It includes pricing and cart widgets.
- Cart: These cards appear within the main cart view and allow users to expand the card and edit quantity via expand/collapse functionality. They may also be removed from the cart outright.
- Hidden content: these cards do not show categorization from ProductInfo.
- CartPreview: These cards appear only within the Task Panel as a “cart preview” for users to see items in their cart before going to the dedicated cart page.
- Hidden content: these cards hide the categorization from ProductInfo and do not show ProductDetailBadges.
- Summary: These cards are intended to reflect products already submitted through the cart. They display necessary product details, what was ordered, and the price.
- Hidden content: these cards do not show stock status as part of ProductDetailBadges.
Usage
Card variants have straightforward naming that makes their usage clear. Be sure to use the right variant for the right context.
Default/grid: product card for PLP settings (grid view)
List: product card for PLP settings (list view)
Carousel: product card for carousels
Cart: product card for the cart page
Cart Preview: product card for the Task Panel cart preview
Summary: product card for post-order submission page
Component Specs
API
- ad:
boolean
| Default:false
Indicates if the product is an ad. - categories:
string[]
| Default:[]
- containerType:
string
| Default:undefined
The type of container the product is in. - hasDiscount:
boolean
| Default:false
- handleBtnClick:
function
| Default:undefined
Callback function for the button click event (carousel). - handleDiscountClick:
function
| Default:undefined
- handlePriceScheduleClick:
function
| Default:undefined
- href:
string
| Default:undefined
The URL to navigate to when the card is clicked. - imageUrl:
string
| Default:undefined
- itemsInCart:
number
| Default:undefined
The number of items in the cart. - materialType:
string
| Default:undefined
- packagingDetail:
boolean
| Default:false
Indicates if the product has packaging details. - priceDetails:
object[]
| Default:[]
- priceSchedule:
string
| Default:undefined
The price schedule of the product. - sizeUnitBadges:
string[]
| Default:[]
- sku:
string
| Default:undefined
- stockStatus:
string
| Default:undefined
The stock status of the product. - testId:
string
| Default:undefined
- title:
string
| Default:undefined
- variant:
string
| Default:grid
The variant of the card.
Example
<script>
import { CardProduct } from '@getprovi/craft-svelte';
const priceDetails = [
{
sizeUnitType: 'unit',
sizeUnitLabel: '750ml',
pricePerOz: '$0.50',
frontlinePrice: '$10.00',
hasDiscount: true,
discountPrice: '$8.00',
cartWidgetProps: {
quantity: 1,
value: 10,
handleChange: () => console.log('handleChange'),
handleInput: () => console.log('handleInput'),
handleMinusClick: () => console.log('handleMinusClick'),
handlePlusClick: () => console.log('handlePlusClick')
}
},
{
sizeUnitType: 'case',
sizeUnitLabel: 'Case of 12',
pricePerOz: '$0.40',
frontlinePrice: '$10.00',
minBottle: true,
cartWidgetProps: {
quantity: 1,
value: 10,
handleChange: () => console.log('handleChange'),
handleInput: () => console.log('handleInput'),
handleMinusClick: () => console.log('handleMinusClick'),
handlePlusClick: () => console.log('handlePlusClick')
}
}
];
</script>
<CardProduct
ad
categories={['Subtype', 'Style']}
href="#"
imageUrl=""
materialType="aluminum"
{priceDetails}
sizeUnitBadges={['750ml', '12 per case', '6 pack']}
sku="123456789"
stockStatus="in"
testId="test-card-product"
title="Product title here may wrap to two lines if needed before it needs to truncate would truncate here"
/>
<CardProduct
ad
categories={['Subtype', 'Style']}
containerType="can"
hasDiscount
href="#"
imageUrl=""
itemsInCart={undefined}
materialType="aluminum"
packagingDetail
priceSchedule="changing"
sizeUnitBadges={['750ml', '12 per case', '6 pack']}
sku="123456789"
stockStatus="in"
testId="test-card-product"
title="Product title here may wrap to two lines if needed before it needs to truncate would truncate here"
variant="carousel"
handleBtnClick={() => console.log('Button clicked')}
handleDiscountClick={() => console.log('Discount clicked')}
handlePriceScheduleClick={() => console.log('Price schedule clicked')}
/>
<CardProduct
variant="cart-preview"
imageUrl=""
itemsInCart="1 Pack"
{href}
{sizeUnitBadges}
{title}
{priceDetails}
totalPrice="$350.28"
totalDiscountPrice="$330.28"
/>
Types
interface SharedProps {
ad?: boolean;
href: string | undefined | null;
imageUrl: ComponentProps<ProductImage>['src'];
testId?: string;
variant?: 'grid' | 'carousel' | 'list' | 'cart' | 'summary';
}
interface Grid extends SharedProps, Omit<GridProps, 'src'> {
itemsInCart?: never;
handleBtnClick?: never;
message?: ProductPriceGroup['message'];
messageDescription?: ProductPriceGroup['messageDescription'];
priceDetails?: PriceDetails[];
}
interface Carousel extends SharedProps, Omit<CarouselProps, 'src'> {
message?: never;
messageDescription?: never;
priceDetails?: never;
itemsInCart?: string;
handleBtnClick: () => void;
}
interface List extends SharedProps, Omit<ListProps, 'src'> {
variant: 'list';
itemsInCart?: never;
handleBtnClick?: never;
handleRemoveClick?: never;
removeBtnType?: never;
totalPrice?: never;
totalDiscountPrice?: never;
}
interface Cart extends SharedProps, Omit<CartProps, 'src'> {
variant: 'cart';
ad?: never;
categories?: never;
message?: never;
messageDescription?: never;
hasDiscount?: never;
priceSchedule?: never;
handleBtnClick?: never;
handleDiscountClick?: never;
handlePriceScheduleClick?: never;
}
interface CartPreview extends SharedProps, Omit<CartPreviewProps, 'src'> {
variant: 'cart-preview';
ad?: never;
categories?: never;
containerType?: never;
materialType?: never;
sku?: never;
stockStatus?: never;
packagingDetail?: never;
message?: never;
messageDescription?: never;
hasDiscount?: never;
priceSchedule?: never;
handleBtnClick?: never;
handleDiscountClick?: never;
handlePriceScheduleClick?: never;
}
interface Summary extends SharedProps, Omit<SummaryProps, 'src'> {
variant: 'summary';
ad?: never;
categories?: never;
message?: never;
messageDescription?: never;
hasDiscount?: never;
priceSchedule?: never;
handleBtnClick?: never;
handleDiscountClick?: never;
handlePriceScheduleClick?: never;
handleRemoveClick?: never;
removeBtnType?: never;
stockStatus?: never;
}
type Variant = Grid | Carousel | List | Cart | CartPreview | Summary;