<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="M12.4907 20.5806C12.4538 20.603 12.4158 20.6259 12.3786 20.6477C12.1434 20.785 11.8519 20.7838 11.6176 20.645L11.5062 20.5774C11.4366 20.5345 11.3359 20.4717 11.2087 20.3901C10.9544 20.227 10.5934 19.9884 10.1613 19.6831C9.2984 19.0734 8.14487 18.193 6.98812 17.1121C4.71943 14.9921 2.25 11.9278 2.25 8.51266C2.25 5.58716 4.58441 3.25 7.5 3.25C9.03842 3.25 10.3421 4.16053 11.1962 4.9489C11.5116 5.24006 11.7824 5.53002 12 5.78205C12.2176 5.53002 12.4884 5.24006 12.8038 4.9489C13.6579 4.16053 14.9616 3.25 16.5 3.25C19.4142 3.25 21.75 5.58579 21.75 8.5C21.75 11.9589 19.283 15.0258 17.0112 17.1406C15.8539 18.218 14.6998 19.0918 13.8365 19.6958C13.4042 19.9983 13.043 20.2343 12.7885 20.3956C12.6612 20.4762 12.5604 20.5382 12.4907 20.5806ZM3.75 8.51266C3.75 11.2516 5.78075 13.9309 8.01225 16.0161C9.10559 17.0378 10.2022 17.8753 11.0268 18.458C11.4296 18.7425 11.7658 18.9651 12.0029 19.1175C12.2398 18.9672 12.5751 18.7476 12.9766 18.4667C13.8007 17.8902 14.8966 17.0598 15.9892 16.0427C18.2172 13.9686 20.25 11.2855 20.25 8.5C20.25 6.41421 18.5858 4.75 16.5 4.75C15.5384 4.75 14.5921 5.33947 13.8212 6.0511C13.4488 6.3949 13.1457 6.74102 12.9356 7.00175C12.8311 7.13154 12.7508 7.23868 12.6977 7.31179C12.6712 7.34831 12.6515 7.37623 12.6391 7.39411L12.626 7.41317L12.624 7.41603C12.4849 7.62448 12.2506 7.75 12 7.75C11.7496 7.75 11.5153 7.62451 11.3762 7.41634L11.374 7.41317L11.3609 7.39411C11.3485 7.37623 11.3288 7.34831 11.3023 7.31179C11.2492 7.23868 11.1689 7.13154 11.0644 7.00175C10.8543 6.74102 10.5512 6.3949 10.1788 6.0511C9.72644 5.63355 9.21372 5.25805 8.67296 5.01901C8.29212 4.85066 7.89737 4.75 7.5 4.75C5.41559 4.75 3.75 6.41284 3.75 8.51266Z" fill="currentColor" />
                </svg>

            </button>

            <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": true,
    "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