ProductGridItem reusable renders a product card for grid/carousel listings (category/search results, related products, carousels). It supports:Components/FilterList/Default.liquidComponents/ProductsBlock/Default.liquidComponents/ProductsCarousel/Default.liquidComponents/RelatedProducts/Default.liquidComponents/Wishlist/Default.liquidComponents/LastVisitedProducts/Default.liquidComponents/ProductComparison/Default.liquid{% render 'Reusables\\ProductGridItem\\Default', product: product, modelId: id, colorExists: colorExists, listName: listName, position: forloop.index0 %}productmodelIdmodelId-product.id) for DOM scoping.colorExistslistNamepositionproductImage from product.mediaItems[0] when available./product/{{ product.alias }}x-data='productgriditemreusabledefault.initComponent({{ product | serialize | escape }}, "{{ Reusables.ProductGridItem.Translations.AddToCartErrorMessage }}", "{{ Reusables.ProductGridItem.Translations.UpdateProductQuantityErrorMessage }}")'Reusables/ProductComparisonButtonReusables/WishlistButtonReusables/ShoppingListsButtonGlobalData.Settings.ShowProductComparisonGlobalData.Settings.EnableWishlistGlobalData.Settings.EnableShoppingListsproduct.brand.* exists, the card renders a brand badge (image when available, otherwise text).product.categoryName / product.categoryLink (when present).product.title and links to /product/{{ product.alias }}.product.isMpnVisible and/or product.isSkuVisible.product.productVariants.size > 1.product.dimension1 / product.dimension2 (and their .type, .items).GlobalData.Settings.noImage.link or /Assets/images/no-image.svg.{
"id": "Product Id",
"title": "Sample title",
"alias": "sample",
"categoryName": "Sample text",
"categoryLink": "/category/sample",
"isMpnVisible": true,
"isSkuVisible": true,
"mpn": "Sample text",
"sku": "Sample text",
"mediaItems": [
{
"id": "Media Id",
"link": "https://example.com/sample",
"position": 0,
"alt": "Sample text",
"mediaType": "Image"
},
...
],
"icoTags": [
{
"id": "Tag Id",
"name": "Sample text",
"backgroundColor": "Sample text",
"textColor": "Sample text",
"icon": { "link": "https://example.com/sample" }
},
...
],
"brand": {
"name": "Sample text",
"link": "/brand/sample",
"image": { "link": "https://example.com/sample", "alt": "Sample text" }
},
"dimension1": {
"type": "Color",
"name": "Sample text",
"items": [ { "id": "Dim Item Id", "value": "Sample text", "textColor": "Sample text" }, ... ]
},
"dimension2": {
"type": "Size",
"name": "Sample text",
"items": [ { "id": "Dim Item Id", "value": "Sample text" }, ... ]
},
"productVariants": [
{
"id": "Variant Id",
"dimension1ItemId": "Dim Item Id",
"dimension2ItemId": "Dim Item Id",
"finalPrice": 25,
"finalPriceText": "25,00 €",
"originalPrice": 35,
"originalPriceText": "35,00 €",
"canOrder": true,
"sellOutOfStock": false,
"quantity": 2,
"minOrderQuantity": 1,
"orderQuantityStep": 1
},
...
],
"startPrice": 25,
"startPriceText": "25,00 €",
"hasPriceRange": false,
"inWishlist": false
}Default.liquid):product.id, product.title, product.aliasproduct.categoryName, product.categoryLinkproduct.mediaItems[0].link, product.mediaItems[0].altproduct.icoTags[] (label rendering)product.brand.name, product.brand.link, product.brand.image.link, product.brand.image.altproduct.isMpnVisible, product.mpnproduct.isSkuVisible, product.skuproduct.productVariants (size, iteration, JS state)product.dimension1, product.dimension2 and nested .type, .name, .items[]productgriditemreusabledefaultx-data="productgriditemreusabledefault.initComponent(product, addToCartErrorMessage, updateProductQuantityErrorMessage)"sendSelectEvent(...) and sendSelectEventAndRedirect(...).{{ product | serialize | escape }}). Keep the product payload reasonably sized.dimension1 or dimension2) and sets colorDimKey / otherDimKey.updateSelectedVariant().handleClickEvents().isProductSection is true, also initializes sticky/scroll helpers for product single sections.window.innerWidth < 1440 to determine mobile behavior..product-card__title-cat height and sets the CSS variable --heightTitleCat.selectItem for the clicked product.selectItem and then navigates to /product/${product.alias}.mousedown handler to the card.[data-product-list-double] or [data-product-list])selectItemselectedDimColor* and the corresponding selectedDim1* / selectedDim2*).updateSelectedVariant().selectedDimOther* and the corresponding selectedDim1* / selectedDim2*).updateSelectedVariant().selectedDim1* / selectedDim2*.updateSelectedVariant().selectedVariant and selectedVariantIndex.updateQuantity(...).getActiveImage(...).quantityConstraints.additive.minimum) as the default quantity when a variant is selected.null when not enough dimensions are selected.product.productVariants.length.true.isAdding) and checks canAddToCart().servicesreusabledefault.addToCart(productId, variantId, quantity, finalPrice, originalPrice).$store.toast with addToCartErrorMessage.variant.quantityConstraintsupdateQuantity(...)true when (product.productVariants || []).length > 1.displayStartPrice: used when the product has a price range and dimensions are not fully selected.displayFinalPrice: returns the selected variant price text, or a fallback price text.displayOriginalPrice: returns the selected variant original price text, or a fallback.quantityConstraints.additive.isValid.true if any variant is orderable.true only when selectedVariant.quantityConstraints.additive.isValid.customColorActive when stockAvailability.label === 'Custom' and a color exists.'-' when displayNullLine is true and the value is missing.variantOrDefault('stockAvailability.label').isProductSection === true.activeButton.activeButton.quantity using quantityConstraints.additive.step and min/max.updateQuantity(...) per product id.checkQuantity is true, calls servicesreusabledefault.updateProductQuantity(...) to validate/normalize quantity server-side.checkQuantity is false, it updates this.quantity directly.$store.toast for error feedback when the API call fails.$store.toast (used by related actions like add-to-cart errors)servicesreusabledefault for cart/quantity-related operations (see Reusables/ProductGridItem/Default.js).Reusables/ProductGridItem/Default.liquidReusables/ProductGridItem/Default.jsReusables/ProductGridItem/Default.jsonReusables/ProductComparisonButton/DefaultReusables/WishlistButton/DefaultReusables/ShoppingListsButton/Default/product/{{ product.alias }} on click and on Enter/Space when focused.product.mediaItems[0] is an image; in real data, the first item should be an Image mediaType for best results.