Product card
The PLP unit. Composes badges, an image, SKU + name + compatibility, and a footer with price + stock badge. Adds an action area for the Add-to-cart button. All slots are optional except name + price.
Default
Minimal usable card: image, SKU, name, price, stock, action.
<div class="product-card">
<a href="..." class="product-card__image">
<img src="brush.jpg" alt="">
</a>
<div class="product-card__body">
<div class="product-card__sku">SKU · BRU-20-SOFT</div>
<a href="..." class="product-card__name">20" soft nylon disc brush, pack of 2</a>
<div class="product-card__footer">
<div class="product-card__price">$42.40</div>
<span class="stock-badge stock-in">In stock</span>
</div>
</div>
<div class="product-card__action">
<button class="btn btn-brand btn-sm btn-full">Add to cart</button>
</div>
</div>With badges
Badges stack vertically in the top-left corner. Three available types: OEM (brand blue), Subscription (gold), New (black).
<div class="product-card">
<div class="product-card__badges">
<span class="product-card__badge-oem">OEM</span>
<!-- or product-card__badge-sub for SUB, product-card__badge-new for NEW -->
</div>
...
</div>Stock states
Stock badge in the footer reflects inventory truth. For low / out / backordered, consider also disabling or modifying the action button.
<!-- Low stock -->
<span class="stock-badge stock-low">3 left</span>
<!-- Out — disable the primary action -->
<span class="stock-badge stock-out">Out</span>
<button class="btn btn-ghost btn-sm btn-full" disabled>Notify me</button>
<!-- Backordered with ETA -->
<span class="stock-badge stock-back">ETA Mar 18</span>
<button class="btn btn-outline btn-sm btn-full">Pre-order</button>With wishlist + compatibility note
The wishlist heart sits in the top-right corner over the image. The compat slot fits between the name and the footer for "fits Tennant T7" guidance.
<div class="product-card">
<div class="product-card__badges">
<span class="product-card__badge-oem">OEM</span>
</div>
<button class="product-card__wishlist" aria-label="Add to wishlist">
<svg ...>...</svg>
</button>
<a href="..." class="product-card__image">...</a>
<div class="product-card__body">
<div class="product-card__sku">SKU · BRU-20-SOFT</div>
<a href="..." class="product-card__name">20" soft nylon disc brush, pack of 2</a>
<div class="product-card__compat">✓ Fits your Tennant T500e</div>
<div class="product-card__footer">
<div class="product-card__price">$42.40</div>
<span class="stock-badge stock-in">In stock</span>
</div>
</div>
<div class="product-card__action">
<button class="btn btn-brand btn-sm btn-full">Add to cart</button>
</div>
</div>In a grid — PLP context
Cards in a 4-column grid mirror the live PLP. They stretch to equal heights via the flex column layout.
Anatomy
Slot reference and structural rules.
| Slot | Class | Required | Notes |
|---|---|---|---|
| Container | .product-card | Yes | Sets layout, shadow, hover state |
| Badges | .product-card__badges | No | Stack vertically in top-left |
| Wishlist | .product-card__wishlist | No | Top-right corner over image |
| Image | .product-card__image | Yes | 1:1 aspect ratio enforced |
| Body | .product-card__body | Yes | Flex column, gap: spacing.2 |
| SKU | .product-card__sku | No | 12px muted text |
| Name | .product-card__name | Yes | Use an <a> for the click target |
| Compat note | .product-card__compat | No | Single line above footer |
| Footer | .product-card__footer | Yes | Price + stock badge, justified |
| Action | .product-card__action | No | Houses the Add-to-cart button |