Implementing Flexible Sized Grid Items in Magento 2 with Luma

Note: This article is an implementation suggestion based on the Magento2Tweakwise module. The actual implementation depends on the specifications and requirements of your platform. Use this as a starting point and adapt it to your specific project setup.


Prerequisites

Before you begin, make sure you have:


How it works

When Flexible Sized Grid Items are enabled in the Merchandising Builder, the Tweakwise API returns visualproperties (with colspan and rowspan) for each item in the response. The Magento 2 Tweakwise module parses these values and attaches them to the product object in the collection. Your frontend templates and CSS are then responsible for translating colspan and rowspan into CSS Grid properties (grid-column: span X and grid-row: span Y).

For more details on the API response format, see Flexible Sized Grid Items.


Implementation

The implementation consists of two parts:

  1. Product item template — Read visual properties and apply inline grid styles to each product <li>.
  2. Visual item template — Apply the same grid styles to visual (non-product) items.

Step 1: Modify the product item template

In view/frontend/templates/product/list/item.phtml, add the following logic to read colspan and rowspan from the product and build an inline style:

use Tweakwise\Magento2Tweakwise\Model\Client\Type\ItemType;

// Build inline grid-column / grid-row spans from Tweakwise visualproperties
// (colspan/rowspan) so the product list grid honors the configured layout.
$gridStyle = '';
$colspan = (int) $_product->getData(ItemType::COLSPAN);
if ($colspan > 1) {
    $gridStyle .= 'grid-column: span ' . $colspan . ';';
}
$rowspan = (int) $_product->getData(ItemType::ROWSPAN);
if ($rowspan > 1) {
    $gridStyle .= 'grid-row: span ' . $rowspan . ';';
}

Then apply the style to the <li> element:

<li class="item product product-item"<?= $gridStyle ? ' style="' . $escaper->escapeHtmlAttr($gridStyle) . '"' : '' ?>>

Step 2: Modify the visual item template

In view/frontend/templates/product/list/visual.phtml, add the same logic using the Visual model's getter methods:

// Build inline grid-column / grid-row spans from Tweakwise visualproperties
// (colspan/rowspan) so the product list grid honors the configured layout.
$gridStyle = '';
$colspan = (int) $visual->getColspan();
if ($colspan > 1) {
    $gridStyle .= 'grid-column: span ' . $colspan . ';';
}
$rowspan = (int) $visual->getRowspan();
if ($rowspan > 1) {
    $gridStyle .= 'grid-row: span ' . $rowspan . ';';
}

Then apply the style to the <li> element:

<li class="item product product-item"<?= $gridStyle ? ' style="' . $escaper->escapeHtmlAttr($gridStyle) . '"' : '' ?>>

Step 3: Set up CSS Grid on your product list container

For the inline grid-column and grid-row styles to take effect, your product list container must use CSS Grid as its layout system. Luma's default product grid uses inline-block and fixed percentage widths, so you will need to override this with a CSS Grid layout.

Add a LESS file at view/frontend/web/css/style.less with the following CSS Grid override:


.products-grid .products.list.items.product-items,
.products.list.items.product-items.product-items {
    display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    grid-auto-flow: row dense;
    grid-auto-rows: 1fr;
    gap: 20px;
    list-style: none;
    padding: 0;
    margin: 0;

    &::before,
    &::after {
        content: none;
    }

    > .item.product.product-item {
        display: flex !important;
        flex-direction: column;
        width: auto !important;
        margin: 0 !important;
        padding: 0;
        float: none !important;

        .product-item-info,
        .visual,
        .visual-image {
            width: 100%;
            height: 100%;
        }

        .visual-image {
            object-fit: cover;
        }
    }

    .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
        grid-template-columns: repeat(2, 1fr);

        > .item.product.product-item {
            grid-column: span 1 !important;
        }
    }

    .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
        grid-template-columns: 1fr;

        > .item.product.product-item {
            grid-column: span 1 !important;
            grid-row: span 1 !important;
        }
    }
}

Reference