Home
Wiki
Home
Wiki
  1. 3. Reusables
  • Back to home
  • 1. Themes
  • Vs Code
    • Getting Started
  • Kitchenware
    • Layout
      • New Layout
      • Legacy Layout
    • Components
      • Announcement
      • Banner Carousel
      • Banner With Products Carousel
      • Blog Category List
      • Blog List
      • Brand List
      • Brands Carousel
      • Breadcrumb
      • Call To Action
      • Cart
      • Categories List
      • Change Password
      • Checkout
      • Cookie Manager
      • Filter list
      • Footer
      • Forgot Password
      • Form
      • Hero Carousel
      • Icon Block
      • Invitation
      • Last Visited Products
      • Layout
      • Login
      • Map
      • Nav Bar
      • Offer
      • Product Attachments
      • Product Attributes
      • Product Documentation
      • Product Expected
      • Product Modal
      • Products Block
      • Products Carousel
      • Product Single
      • Profile
      • Quote
      • Register
      • Related Products
      • Search
      • Stores
      • Subscribe Newsletter
      • Text with Image
      • Top Bar
      • Video
    • Reusables
      • Getting Started
    • Assets
      • Getting Started
    • SDK
      • Products
        • _findProductsByCategory
        • _findProductsByIds
        • _findProductsByTitle
        • _findProductsByFilter
        • _findProductsByCriteria
        • _findProductsAndCalculate
        • _findProductsThenCalculate
        • _getProductAttributeSet
        • _setLastVisited
      • Categories
        • _findCategoryTreeById
        • _findCategoriesByIds
        • _findCategoryByAlias
        • _findCategoryTreeByAlias
        • _getCategoryContent
      • Collections
        • _getCollectionContent
        • _findCollectionsByIds
        • _findCollectionsByIdsThenCalculate
      • Brands
        • _getBrandContent
        • _findBrandsByIds
      • Cart
        • _addToCartMulti
        • _addToCart
        • _setCart
        • _clearCart
        • _setCartListener
        • _removeFromCart
        • _calculateCart
      • Checkout
        • _startCheckout
        • _updateCheckout
        • _completeCheckout
      • Shopping Lists
        • _getShoppingLists
        • _updateShoppingList
        • _createShoppingList
        • _deleteShoppingList
        • _getShoppingListByAlias
      • Navigation
        • _getFooterMenu
        • _getHeaderMenu
      • Users
        • _getUserById
      • Utils
        • _calculateCurrency
        • _getCurrencySymbol
        • _getCulture
        • _subscribeToNewsletter
        • _findUnitsByIds
  • Noir
    • 0. Introduction
    • 1. Structure
      • Overview
      • LayoutA.liquid
      • ComponentsList.liquid
      • Metas.liquid
      • CssVariables.liquid
      • Json.liquid
      • GoogleTagManager.liquid
      • StagingButton.liquid
    • 2. Components
      • Overview
      • Announcement
      • BannerCarousel
      • BlogCategoryList
      • BlogList
      • BrandList
      • Breadcrumb
      • Cart
      • CategoriesList
      • ChangePassword
      • Checkout
      • CookieManager
      • FilterList
      • Footer
      • ForgotPassword
      • Form
      • IconBlock
      • Invitation
      • LastVisitedProducts
      • Login
      • Map
      • NavBar
      • ProductAttachments
      • ProductAttributes
      • ProductComparison
      • ProductDocumentation
      • ProductMixList
      • ProductsBlock
      • ProductsCarousel
      • ProductSingle
      • Profile
      • Register
      • RelatedProducts
      • SingleBlog
      • Stores
      • TextWithImage
      • ThankYouPage
      • TopBar
      • Wishlist
    • 3. Reusables
      • Overview
      • Addresses
      • BillingRetail
      • AddressForm
      • AnnouncementModal
      • BackToTop
      • Company
      • General
      • Login
      • LoginModal
      • Orders
      • Payment
      • ProductAttachments
      • ProductAttributes
      • ProductComparisonButton
      • ProductComparisonFloatingButton
      • ProductGridItem
      • ProductListItem
      • ShoppingListsButton
      • ProductModal
      • ProfileInfo
      • PromptModal
      • Register
      • Shipping
      • ShoppingLists
      • ShoppingListsNavbar
      • Toast
      • Users
      • VariantContent
      • WishlistButton
      • Services
    • 4. Assets
      • Fonts
      • Images
      • Templates
      • Javascript
        • Overview
        • theme.js
      • Css / Scss
        • Overview
        • ThemeClasses
    • 5. SDK
      • Overview
      • LiquidGlobals
      • ServicesSDK
  1. 3. Reusables

VariantContent

Purpose#

The VariantContent reusable renders product variant selection UI (dimensions like Color/Size), plus basic product header info (category/title/image) and an Add to cart action.
It is designed to be used inside the Product modal flow and reads its main input from the global Alpine store $store.productModal.product.
It has two rendering modes:
Default mode (used in the product modal / quick view)
quickAddModal: true mode (used in Cart for a compact “available variants” experience)

Where it's rendered#

This reusable is rendered in at least these places:
Reusables/ProductGridItem/Default.liquid
{% render 'Reusables\\VariantContent\\Default' %}
Components/Cart/Default.liquid
{% render 'Reusables\\VariantContent\\Default', quickAddModal: true %}

What these two render sites correspond to in the UI#

Based on the two render sites above, VariantContent is used in two distinct UI contexts:
1.
Cart: “quick add / available variants” modal-like content
Render site: Components/Cart/Default.liquid with quickAddModal: true.
Used in the cart flow to present a compact variant-picker UI.
In this mode, the reusable emphasizes:
the AvailableVariants title
a product image
the dimensions UI (Color/Size etc.)
The JS also resets selection state when the modal product changes.
2.
Product cards (product grid item / quick view)
Render site: Reusables/ProductGridItem/Default.liquid.
This is the “product card” context, where VariantContent is used as part of the product tile/quick-view behavior.
Whether it shows as an inline UI, a modal, or a mobile-only pattern depends on the surrounding markup/behavior in ProductGridItem and the product-modal store; VariantContent itself just reads $store.productModal.product and renders accordingly.

Inputs (Liquid render parameters)#

Optional Liquid render parameter:
quickAddModal (boolean)
When true, the template shows the “Available variants” title and a product image block at the top.
The JS receives isQuickAddModal = true and resets selection state when the modal product changes.
Main data input (not a render parameter):
$store.productModal.product
The template mounts only when a product exists:
<template x-if="$store.productModal.product">
  <div x-data="variantcontentreusabledefault.initComponent($store.productModal.product, true)">
    ...
  </div>
</template>

Model shape (storefront example)#

Below is a real runtime sample of $store.productModal.product that you provided (sanitized by collapsing long arrays like searchAttributes and productVariants).
Sanitized storefront sample:
{
  "vatIncluded": false,
  "vatRate": 25,
  "reducedVatRate": 5,
  "isMpnVisible": true,
  "isSkuVisible": true,
  "title": "Λευκή Μπλούζα Γυναικεία",
  "alias": "lefki-blouza-gynaikeia",
  "status": "Active",
  "categoryId": "e8b0acbf-95dd-477c-9c93-fda01751cfd2",
  "categoryName": "Μπλούζες - Τοπ",
  "categoryLink": "/category/blouzes-top",
  "availability": "Unavailable",
  "id": "2014b559-d193-46e7-9fe6-f6b4b1a8e9d4",
  "companyId": "a6cf8a64-13dc-45f7-bc04-d7591f3e927a",
  "link": "product/lefki-blouza-gynaikeia",
  "mediaItems": [
    {
      "id": "3cfd3be2-3e21-45db-b231-479affa0a56e",
      "link": "https://ecom-media.azureedge.net/...",
      "position": 0,
      "alt": "product-woman-top-4.jpg",
      "mediaType": "Image"
    },
    {
      "id": "ad1ca4c2-6cb4-47b2-9e7b-6518f67f9b81",
      "link": "https://ecom-media.azureedge.net/...",
      "position": 1,
      "alt": "green.pdf",
      "mediaType": "Attachment"
    }
  ],
  "variantCount": 24,
  "productVariants": [
    {
      "id": "1a616222-7f73-4daa-93a9-c53562f3c7eb",
      "dimension1ItemId": "64575851-be25-428e-8a1f-aaf1e13dfddf",
      "dimension2ItemId": "e871b942-b888-487d-bd3e-79aa4b54c79b",
      "sku": "kokkino-medium",
      "sellOutOfStock": true,
      "canOrder": true,
      "startQuantity": 1,
      "price": 0,
      "unitPrice": 0
    },
    {
      "id": "1251d588-b783-403b-a046-644368c565cc",
      "dimension1ItemId": "dd22993a-3ba8-4a0a-9534-7ed9b1159e54",
      "dimension2ItemId": "720fc539-fb43-4b09-a8a0-78d66a577cab",
      "sellOutOfStock": true,
      "canOrder": true,
      "startQuantity": 1,
      "price": 25,
      "unitPrice": 25,
      "finalPriceText": "25,00 €",
      "finalPrice": 25
    },
    {
      "id": "9c1c0658-09c9-493f-bcc7-8a0e7567abf1",
      "dimension1ItemId": "34da3422-bbc3-481f-82ac-13216a3b4fa9",
      "dimension2ItemId": "e871b942-b888-487d-bd3e-79aa4b54c79b",
      "gtin": "12334566",
      "mpn": "12334566",
      "sku": "12334566",
      "sellOutOfStock": true,
      "canOrder": true,
      "startQuantity": 1,
      "price": 50,
      "unitPrice": 50,
      "finalPriceText": "50,00 €",
      "finalPrice": 50
    }
  ],
  "dimension1": {
    "name": "Χρώμα",
    "type": "Color",
    "items": [
      { "id": "34da3422-bbc3-481f-82ac-13216a3b4fa9", "value": "Μαύρο", "textColor": "#000000" },
      { "id": "64575851-be25-428e-8a1f-aaf1e13dfddf", "value": "Κόκκινο", "textColor": "#d64343" },
      { "id": "dd22993a-3ba8-4a0a-9534-7ed9b1159e54", "value": "Πράσινο", "textColor": "#1aa189" }
    ]
  },
  "dimension2": {
    "name": "Μέγεθος",
    "type": "Size",
    "items": [
      { "id": "13556de0-3fda-49ef-af16-2a4cef5d50e1", "value": "S" },
      { "id": "e871b942-b888-487d-bd3e-79aa4b54c79b", "value": "M" },
      { "id": "720fc539-fb43-4b09-a8a0-78d66a577cab", "value": "L" },
      { "id": "a2591652-4bc6-476a-a6f8-cde433d7bdfd", "value": "XL" }
    ]
  },
  "hasPriceRange": false,
  "inWishlist": false
}

Template behavior (Liquid + Alpine)#

Product header#

Shows category name (as a link when product.categoryLink exists).
Shows the title via variantOrDefault('title').
When quickAddModal: true:
Shows the AvailableVariants heading.
Renders a product image linking to /product/${product.alias}.

MPN / SKU#

When not in quickAdd mode, the template can show MPN/SKU based on feature flags:
product.isMpnVisible → prints variantOrDefault('mpn', true)
product.isSkuVisible → prints variantOrDefault('sku', true)
If a value isn’t available and displayNullLine = true, variantOrDefault returns -.

Dimensions UI (Color + Other)#

The template displays up to two dimensions (product.dimension1, product.dimension2).
If one of them has type === 'Color', it is treated as the color dimension.
The other one (if present) is displayed as the other dimension (often Size).
Each dimension is rendered in a Swiper carousel, initialized with:
Buttons are disabled based on orderability checks (implemented in JS) and selection state is highlighted.

JavaScript#

Reusable JS file#

Reusables/VariantContent/Default.js defines:
variantcontentreusabledefault.initComponent(product, isQuickAddModal = false)
variantcontentreusabledefault.initSwiper(refs)
Key behaviors:
Watches for changes to Alpine.store('productModal').product and re-initializes the selection UI.
Identifies which dimension is Color vs Other (colorDimKey / otherDimKey).
Tracks selections (selectedDim1Id, selectedDim2Id, plus color/other labels).

Variant selection#

Selection attempts to find a matching variant based on chosen dimension item ids:
dimension1ItemId must match selectedDim1Id (when product.dimension1 exists)
dimension2ItemId must match selectedDim2Id (when product.dimension2 exists)
The active variant influences variantOrDefault(path) resolution.

variantOrDefault(path, displayNullLine)#

This helper returns the first non-empty value found in:
1.
The selected variant (product.productVariants[selectedVariantIndex])
2.
The product object (product)
If nothing is found:
returns - when displayNullLine = true
otherwise returns the (likely empty/undefined) product value
Implementation notes (from the real code):
path can be either a string like 'sku' or 'quantityConstraints.additive.minimum' or an array of path segments.
The function also toggles this.customColorActive when the object being read has:
stockAvailability.label === 'Custom' and a truthy stockAvailability.color.

Add to cart#

handleAddToCart(closeModal = false) clears toasts and then proceeds only if canAddToCart() allows it.
It calls the following concrete service method (from the real code):
servicesreusabledefault.addToCart(productId, variantId, minQty, finalPrice, originalPrice, showPopUp)
Where:
productId is this.product.id
variantId is variant.id (from this.product.productVariants[this.selectedVariantIndex])
minQty is variant?.quantityConstraints?.additive?.minimum
finalPrice is variant.finalPrice
originalPrice is variant.originalPrice
showPopUp is set based on closeModal
On failure it shows:
$store.toast.add(addToCartErrorMessage, 'ic-warning', 'error')
After a successful add:
It optionally closes $store.productModal (when closeModal is true)
It finds the matching cart item in response.data.cartItems and updates:
variant.quantityConstraints = addedProduct?.quantityConstraints
It calls updateQuantity(...) using the minimum additive quantity from the server:
updateQuantity(addedProduct?.quantityConstraints?.additive?.minimum, addedProduct, addedProduct.productVariantId)

Global Alpine stores#

This reusable uses:
$store.productModal
product
$store.toast
removeAll()
add(...) (for errors/success feedback)

Services / API calls#

The JS integrates with servicesreusabledefault for add-to-cart and quantity-validation operations.
Concrete methods used (from the real code):
servicesreusabledefault.addToCart(...)
servicesreusabledefault.updateProductQuantity(data, cancelToken)
data shape used by this reusable:
productId: product.productId || product.id
productVariantId
requestedQuantity
cancelToken is an Axios cancel token (axios.CancelToken.source().token)
Error feedback (runtime variables used by this reusable):
addToCartErrorMessage (toast on add-to-cart failure)
updateProductQuantityErrorMessage (toast on quantity update failure)
As with the rest of the theme, the reusable treats a response as failure when:
response.status < 200 || response.status >= 300 || response?.success === false

Dependencies#

Liquid: Reusables/VariantContent/Default.liquid
JS: Reusables/VariantContent/Default.js
Translations: Reusables/VariantContent/Default.json (consumed as Reusables.VariantContent.Translations.*)
Vendor:
Swiper (used for dimension carousels)

Notes#

Image rendering uses product.mediaItems[0].link when present; otherwise it falls back to GlobalData.Settings.noImage.link or the theme fallback /Assets/images/no-image.svg.
Color items use item.textColor; the template supports one or two concatenated hex colors (e.g. #RRGGBB#RRGGBB) and renders split halves.
Modified at 2026-04-14 13:18:56
Previous
Users
Next
WishlistButton
Built with