<div class="flex flex-col space-y-4 ">
    <a href="#" class="block relative aspect-square overflow-hidden bg-gray-100 rounded-lg group hover:after:!h-0 noAbsolute">
        <div class="relative w-full h-full">
            <img src="/img/hero/videoLeft.jpg" alt="Product Name" class="w-full h-full object-cover transition-all duration-300 absolute inset-0  group-hover:opacity-0 ">
            <img src="/img/hero/videoRight.jpg" alt="Product Name - Vue alternative" class="w-full h-full object-cover transition-all duration-300 absolute inset-0 opacity-0 group-hover:opacity-100">
        </div>

        <div class="absolute bottom-4 right-1/2 flex space-x-4 translate-x-2/4 duration-300 z-20">

            <button type="button" class="group-hover:!btn-dark-ghost  btn btn-light-ghost btn-size-sm btn-only-icon">
                <svg class=" shrink-0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path fill-rule="evenodd" clip-rule="evenodd" d="M6.5 4.25C3.87665 4.25 1.75 6.37665 1.75 9V15C1.75 17.6234 3.87665 19.75 6.5 19.75H12.5C14.7589 19.75 16.6495 18.1732 17.1312 16.0603L19.8501 17.1478C20.9996 17.6076 22.25 16.7611 22.25 15.523V12V8.47706C22.25 7.239 20.9996 6.39242 19.8501 6.85223L17.1312 7.93976C16.6495 5.82679 14.7589 4.25 12.5 4.25H6.5ZM17.25 9.5078L20.4072 8.24494C20.5714 8.17925 20.75 8.30019 20.75 8.47706V12V15.523C20.75 15.6999 20.5714 15.8208 20.4072 15.7551L17.25 14.4923V9.5078ZM15.75 9.33854V14.6615V15C15.75 16.7949 14.2949 18.25 12.5 18.25H6.5C4.70507 18.25 3.25 16.7949 3.25 15V9C3.25 7.20507 4.70507 5.75 6.5 5.75H12.5C14.2949 5.75 15.75 7.20507 15.75 9V9.33854Z" fill="currentColor" />
                </svg>

            </button>
        </div>
    </a>

    <div class="px-2">
        <p class="text-xxs font-semibold text-neutral-500">Brand Name</p>

        <h3 class="font-semibold text-neutral-800 pt-0.5">Product Name</h3>

        <p class="text-xs text-neutral-500 pt-1">Product description goes here with some details about the item.</p>

        <div class="pt-3">
            <p class="text-[9px] text-neutral-500">Prix web</p>

            <div class="flex items-center gap-2">
                <p class="font-semibold text-neutral-800">
                    99.99 €
                </p>

            </div>
        </div>

    </div>
</div>
{# components/slide/slideCard.twig #}
<div
        class="flex flex-col space-y-4 {{ class }}"
>
    <a
            href="{{ slide.url }}"
            class="block relative aspect-square overflow-hidden bg-gray-100 rounded-lg group hover:after:!h-0 noAbsolute"
            {% if slide.openInNewTab %}target="_blank"{% endif %}
    >
        <div class="relative w-full h-full">
            <img
                    src="{{ slide.image }}"
                    alt="{{ slide.name }}"
                    class="w-full h-full object-cover transition-all duration-300 absolute inset-0 {% if slide.hoverImage is defined and slide.hoverImage %} group-hover:opacity-0 {% endif %}"
            >
            {% if slide.hoverImage is defined and slide.hoverImage %}
                <img
                        src="{{ slide.hoverImage }}"
                        alt="{{ slide.name }} - Vue alternative"
                        class="w-full h-full object-cover transition-all duration-300 absolute inset-0 opacity-0 group-hover:opacity-100"
                >
            {% endif %}
        </div>

        <div class="absolute bottom-4 right-1/2 flex space-x-4 translate-x-2/4 duration-300 z-20">
            {% if slide.showActionButtons is not defined or slide.showActionButtons %}
                {% if slide.showFavoriteButton is not defined or slide.showFavoriteButton %}
                    {% render "@template-button" with {
                        color: slide.buttonColor ~ "-ghost",
                        size: "sm",
                        type: "only-icon",
                        icon: {
                            name: "library--like-outline"
                        },
                        button_class: "group-hover:!btn-" ~ slide.buttonColorHover ~ "-ghost"
                    } %}
                {% endif %}

                {% if slide.showQuickViewButton is not defined or slide.showQuickViewButton %}
                    {% render "@template-button" with {
                        color: "light-ghost",
                        size: "sm",
                        type: "only-icon",
                        icon: {
                            name: "library--camera"
                        },
                        button_class: "group-hover:!btn-dark-ghost"

                    } %}
                {% endif %}
            {% endif %}
        </div>
    </a>

    <div class="px-2">
        {% if slide.brand is defined and slide.brand %}
            <p class="text-xxs font-semibold text-neutral-500" {{ slide.alpineAttribute.slideInfo.brand }}>{{ slide.brand }}</p>
        {% endif %}

        {% if slide.inlinePrice is defined and slide.inlinePrice %}
            <div class="flex justify-between items-end py-2">
                {% if slide.name is defined and slide.name %}
                    <h3 class="font-semibold text-neutral-800 pt-0.5" {{ slide.alpineAttribute.slideInfo.name }}>{{ slide.name }}</h3>
                {% endif %}
                <div class="flex flex-col text-right">
                    {% if slide.webLabel is defined and slide.webLabel %}
                        <span class="text-[9px] text-neutral-500 leading-[0] uppercase" {{ slide.alpineAttribute.slideInfo.webLabel }}>{{ slide.webLabel }}</span>
                    {% endif %}

                    {% if slide.price is defined and slide.price %}
                        <span class="font-semibold text-neutral-800" {{ slide.alpineAttribute.slideInfo.price }}>
                            {{ slide.price }}</span>
                    {% endif %}
                </div>

            </div>
        {% else %}
            {% if slide.name is defined and slide.name %}
                <h3 class="font-semibold text-neutral-800 pt-0.5" {{ slide.alpineAttribute.slideInfo.name }}>{{ slide.name }}</h3>
            {% endif %}
        {% endif %}


        {% if slide.description is defined and slide.description %}
            <p class="text-xs text-neutral-500 pt-1" {{ slide.alpineAttribute.slideInfo.description }}>{{ slide.description }}</p>
        {% endif %}

        {% if slide.colors is defined and slide.colors %}
            <p class="text-xs text-neutral-500 pt-2" {{ slide.alpineAttribute.slideInfo.colors }}>{{ slide.colors }}</p>
        {% endif %}

        {% if not (slide.inlinePrice is defined and slide.inlinePrice) %}
            <div class="pt-3">
                <p class="text-[9px] text-neutral-500" {{ slide.alpineAttribute.slideInfo.webLabel }}>{{ slide.webLabel }}</p>

                <div class="flex items-center gap-2">
                    <p class="font-semibold text-neutral-800" {{ slide.alpineAttribute.slideInfo.price }}>
                        {{ slide.price }}</p>

                    {% if slide.oldPrice and slide.discountText %}
                        <p class="text-neutral-500 text-xs line-through">
                            {{ slide.oldPrice }}</p>
                        <p class="text-green-700 text-xs">
                            {{ slide.discountText }}
                        </p>
                    {% endif %}
                </div>
            </div>
        {% endif %}

        {% if slide.addCart is defined and slide.addCart %}
            <div class="flex justify-center">
                {% render "@template-button" with {
                    label: "Ajouter au panier",
                    color: "dark-ghost",
                    size:"sm"
                } %}
            </div>
        {% endif %}
    </div>
</div>
{
  "slide": {
    "id": "123",
    "url": "#",
    "image": "/img/hero/videoLeft.jpg",
    "hoverImage": "/img/hero/videoRight.jpg",
    "brand": "Brand Name",
    "name": "Product Name",
    "description": "Product description goes here with some details about the item.",
    "color": "3 couleurs disponibles",
    "webLabel": "Prix web",
    "price": "99.99",
    "openInNewTab": false,
    "showActionButtons": true,
    "showFavoriteButton": false,
    "showQuickViewButton": true,
    "class": "",
    "buttonColor": "light",
    "buttonColorHover": "dark"
  }
}

Product Card

The Product Card component is used to display product information in a standardized layout. It is particularly suited for product grids, carousels, and recommendation lists.

Overview

The component displays:

  • A main image with hover effect
  • The product brand
  • The product name
  • A description
  • Available color options
  • Web label (e.g., “Web Price”)
  • The price
  • Optional action buttons (favorites and quick view)

Configuration

Layout Wrapper

meta: {
  layout_wrapper_class: 'inline-grid grid-cols-1 md:grid-cols-3 xl:grid-cols-6 gap-10'
}

This configuration displays product cards in a responsive grid:

  • 1 column on mobile
  • 3 columns on tablets
  • 6 columns on desktops

Props

Prop Type Required Default Description
id string Yes - Unique product identifier
url string Yes ‘#’ URL of the product page
image string Yes - URL of the main image
hoverImage string No null URL of the image displayed on hover
brand string Yes - Brand name
name string Yes - Product name
description string No - Short product description
color string No - Text indicating available colors
webLabel string No - Price label (e.g., “Web Price”)
price string Yes - Product price
openInNewTab boolean No false Opens the link in a new tab
showActionButtons boolean No true Enables/disables all action buttons
showFavoriteButton boolean No true Enables/disables the favorite button
showQuickViewButton boolean No true Enables/disables the quick view button
class string No “” Additional CSS classes

Standard Configuration Example

context: {
  product: {
    id: '123',
    url: '#',
    image: '/img/hero/videoLeft.jpg',
    hoverImage: '/img/hero/videoRight.jpg',
    brand: 'Brand Name',
    name: 'Product Name',
    description: 'Product description goes here with some details about the item.',
    color: '3 colors available',
    webLabel: 'Web Price',
    price: '99.99',
    openInNewTab: false,
    showActionButtons: true,
    showFavoriteButton: true,
    showQuickViewButton: true,
    class: ""
  }
}

Usage

Basic

{% render "@product-card" with { product: product } %}

With Variant

{% render "@product-card--without-buttons" with { product: product } %}

With Custom Classes

{% render "@product-card" with { 
    product: {
        ...product,
        class: "my-custom-class"
    }
} %}

Behavior

  1. Hover Image

    • On hovering over the card, an alternate image fades in if hoverImage is defined
    • Without hoverImage, a zoom effect is applied to the main image
  2. Action Buttons

    • Buttons are positioned at the bottom of the image
    • Visible only if showActionButtons is true
    • Each button can be individually controlled with showFavoriteButton and showQuickViewButton
  3. Navigation

    • Clicking on the card redirects to the product URL
    • Option to open in a new tab via openInNewTab