More Cards Snippets
Product Card — Free HTML CSS JS E-commerce Snippet
Product Card · Cards · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Product Card — Colour Swatches, Wishlist Toggle & Add to Cart Feedback

A product card displays a product image, name, price, colour variants, rating, and an add-to-cart CTA in a compact format. It is the core unit of any e-commerce listing, marketplace, or product catalogue, and feeds the mini cart on add.
Colour swatches
Swatch divs have a data-colour attribute and a click listener that removes .active from all swatches then adds it to the clicked one. The CSS .swatch.active applies a ring via outline: 2px solid offset from the swatch border.
Wishlist toggle
The heart button calls toggleWish() which toggles .liked on the button — the same interaction as the standalone favorite button. CSS .wish.liked svg { fill: #ef4444; stroke: #ef4444 } makes the heart fill red when active. The state is purely visual — wire to an API or localStorage for persistence.
Add to Cart feedback
addToCart(btn) changes btn.textContent to "✓ Added!" and adds .added (green background). A setTimeout after 1.5s resets both. This prevents duplicate submissions and confirms the action without a modal.
Badge positioning
The .badge div uses position: absolute; top: 12px; left: 12px on the .img-wrap parent to overlay a "Sale" or "New" label on the product image.
The colour swatch selector
Each swatch button has a data-colour attribute. When clicked, updateSwatch(btn) reads btn.dataset.colour and applies it as the product image background colour: productImg.style.background = colour. The active swatch gets .active class which adds a ring indicator. This pattern demonstrates how to build a colour selector that updates visual state without navigating to a new page — the same interaction used on Apple, Nike, and most e-commerce product pages.
The wishlist toggle
The heart button toggles .liked class. In the liked state, the heart SVG switches from outline (fill="none") to filled (fill="currentColor"). The button colour changes from grey to red. This is the standard heart/save pattern. In a real product, the toggle triggers a PATCH request to your API to add or remove the product from the user's saved items.
Add to cart feedback state
Clicking "Add to Cart" shows a brief "Added!" text and green background for 1.5 seconds, then resets. This immediate visual confirmation is important for cart interactions — without it, users often click multiple times believing the first click failed.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to trace every click handler by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the swatch click handler's remove-then-add active class pattern works across a querySelectorAll loop, and why addToCart uses a setTimeout to revert the button's text and class instead of leaving it permanently changed. The same assistant can help optimize it, for example checking whether attaching a separate click listener to every individual swatch is the best approach versus a single delegated listener on the swatch container, or whether the wishlist heart's visual state should persist across a page reload. It's also useful for extending the effect: ask it to add a size selector alongside the color swatches using the same active-toggle pattern, persist the wishlist state to localStorage, or wire the swatch selection to actually swap the product image instead of just the ring indicator. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build an e-commerce product card in plain HTML, CSS, and vanilla JavaScript with color swatches, a wishlist toggle, and add-to-cart feedback — no frameworks.
Requirements:
- A card showing a product image area (with a placeholder icon acceptable as the image), a floating wishlist heart button in one corner, a floating sale-percentage badge in another corner, a brand name, a product title, a star rating with a review count, a current price next to a struck-through original price, a row of color swatch circles, and an add-to-cart button.
- Clicking the wishlist heart button must toggle a "liked" visual state on that button — an outlined heart becomes a filled, colored heart (achieved through a CSS class toggle affecting fill and stroke), with no page reload.
- Clicking any color swatch must remove the active-state ring indicator from every other swatch and apply it only to the clicked one, so exactly one swatch is marked active at any time.
- Clicking the add-to-cart button must change its label text to a confirmation message (like a checkmark plus "Added!"), switch its background color to a distinct success color, and automatically revert both the label and the color back to their original state after roughly two seconds, without requiring another click.
- Style the active swatch's ring so it clearly stands out from unselected swatches, and make sure the sale badge and wishlist button are positioned as overlays on top of the image area using absolute positioning, not affecting the image's own layout.
- Keep every piece of behavior — swatch selection, wishlist toggle, and cart feedback — working independently, so clicking one does not interfere with or reset the state of the others.Step by step
How to Use
- 1Interact with the cardClick the colour swatches, heart wishlist button, and Add to Cart button in the preview to see each interaction.
- 2Update product infoIn the HTML panel, change the product name, price, original price, and rating text.
- 3Change swatch coloursUpdate the background colour on each .swatch div inline style in the HTML panel.
- 4Replace the image placeholderReplace the .img-placeholder div with an <img> tag with object-fit: cover; width: 100%; height: 100%;.
- 5Change the badge textUpdate the .badge text in the HTML and its background colour in the CSS.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Each .swatch div has a click listener. On click, all swatches get .active removed via querySelectorAll, then .active is added to the clicked swatch. CSS .swatch.active applies a ring via outline: 2px solid at 2px offset.
In toggleWish(), save the state to localStorage: localStorage.setItem("wish-productId", btn.classList.contains("liked")). On page load, read the value and apply .liked if true.
In addToCart(btn), add your cart logic before the visual feedback: cart.push(productId) or fetch("/cart/add", { method: "POST", body: ... }). The visual feedback (textContent change, timeout reset) runs regardless.
Copy the swatch row structure and replace swatches with size buttons (XS, S, M, L, XL). Add .size-btn CSS for the button style and use the same querySelectorAll active pattern.
Replace <div class="img-placeholder">...</div> with <img src="url" alt="Product name" style="width:100%;height:100%;object-fit:cover;" />.
Yes. Click "JSX" for a React component. In React, manage selectedSwatch and isWished in useState. Pass product data as props. Wire the cart action to your cart context or Redux dispatch.