> For the complete documentation index, see [llms.txt](https://docs.digia.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.digia.tech/ui-building-blocks/widgets/scrolling-widgets/masonry-grid.md).

# Masonry Grid

The **Masonry Grid** widget is designed for layouts where items have **varying heights**, such as image galleries, content cards, and mixed-media feeds. Unlike a regular GridView, which maintains straight rows, Masonry Grid focuses on **filling vertical space efficiently** by stacking items in columns with different heights.

{% embed url="<https://youtu.be/xGrECzWFmdM?si=lRFCEsXzBX-GAfSh>" %}

Watch this on Youtube: <https://www.youtube.com/watch?v=xGrECzWFmdM>

This creates an organic, magazine-like layout where each column grows independently, minimizing empty gaps between items.

### Use Cases

A **Masonry Grid** is like a **Pinterest-style layout** where items are arranged in columns with **variable heights**, and they “stack” tightly without fixed row alignment.

Use **Masonry Grid** when:

* **Card Heights Vary**
  * Blog posts or articles with different text lengths
  * Product cards where some have more info/tags than others
  * Testimonial or review cards of different sizes
* **Image-Heavy Layouts**
  * Photo galleries with different image aspect ratios
  * Inspiration boards, portfolios, moodboards
  * UGC / social feeds where content size isn’t uniform
* **Pinterest-style Feeds**
  * Content discovery screens
  * Explore / inspiration pages (recipes, outfits, designs, etc.)

### Core Concepts

#### 1. Dynamic Children Only

The Masonry Grid is **data-driven**.\
You don’t manually drop multiple children inside it. Instead:

* You provide a **JsonArray** as the **Data Source**.
* You design **one child widget template**.
* Masonry Grid automatically repeats that template for each item in the array.

This is the same pattern as ListView and GridView:

* **No static, individually-placed children**
* **Only dynamic content**, generated from a data source
* Internally uses lazy building for performance

{% hint style="info" %}
Note: If you need a **fixed dashboard** layout with precise manual placement, use a `Column` + `Row`, or `Wrap` instead.\
Masonry Grid is specifically designed for dynamic, data-driven content with variable heights.
{% endhint %}

#### 2. Masonry Layout: Column-Based Flow

Masonry Grid arranges items into **columns**, not strict rows.

* **Cross Axis (Columns)**\
  The number of columns is controlled by **Cross Axis Count**.\
  For example, Cross Axis Count: 3 → 3-column masonry layout.
* **Main Axis (Vertical Growth)**\
  Items are placed in the column with the **current smallest height**.\
  This creates a **staggered**, Pinterest-like layout with minimal vertical gaps.

Key differences from GridView:

* GridView → row-based, rows are visually aligned.
* Masonry Grid → column-based, row lines are **not** aligned; each column grows at its own pace.

This makes Masonry ideal when:

* Items have **different heights** (e.g., different image aspect ratios, text lengths).
* You want a **natural, flowing** grid rather than strict, table-like rows.

#### 3. Lazy Building & Performance

Like ListView and GridView with a data source, Masonry Grid uses **lazy rendering**:

* Only items that are visible (or about to become visible) are built.
* This allows you to display **hundreds or thousands of items** smoothly.
* Scrolling remains performant even with mixed-height content.

{% hint style="success" %}
**Performance Tip:** For large masonry feeds, always bind to a **Data Source** and avoid putting heavy layouts inside each item template.
{% endhint %}

### Data Source Property

The **Data Source** defines what the Masonry Grid displays and how many items it contains.

#### How to Configure the Data Source

1. In the properties panel, locate the **Data Source** field.
2. Provide a value that evaluates to a **JsonArray**.

You can configure this in two ways:

**Option 1: Static JsonArray**

Use a fixed JSON array:

```json
[
  { "title": "Image 1", "url": "..." },
  { "title": "Image 2", "url": "..." }
]
```

Best for:

* Prototyping
* Simple demos or fixed, small sets of content

**Option 2: Dynamic Expression**

Bind the Data Source to an expression that returns a JsonArray:

* From an API response:\
  `${apiResponse.data.images}`
* From app state:\
  `${appState.galleryItems}`
* From a variable:\
  `${masonryData}`

When the underlying data changes, the Masonry Grid updates automatically.

#### Accessing Item Data with `currentItem`

Inside the item template, you can use:

* `currentItem` → The data for the current item.
* `index` → The zero-based index of the current item.

Examples:

* For objects:\
  `${currentItem.imageUrl}`, `${currentItem.title}`, `${currentItem.height}`
* For simple values:\
  `${currentItem}` (when the array contains strings, numbers, etc.)

Bind `currentItem` fields to images, text, badges, and other UI elements in your tile/card.

{% hint style="warning" %}
**Important:** The Data Source **must be a JsonArray**.\
If it’s not an array or expression is invalid, Masonry Grid will not render items.
{% endhint %}

### Properties

| Property             | Description                                                                                        |
| -------------------- | -------------------------------------------------------------------------------------------------- |
| `Data Source`        | JsonArray of items to render. Each entry becomes one masonry tile using the child widget template. |
| `Child Template`     | The single widget layout that is repeated for every item in the Data Source.                       |
| `Cross Axis Count`   | Number of **columns** in the masonry grid (e.g. 2 or 3 for mobile layouts).                        |
| `Main Axis Spacing`  | Vertical space (in pixels) between items stacked within the same column.                           |
| `Cross Axis Spacing` | Horizontal space (in pixels) between columns.                                                      |
| `Padding / Margin`   | Optional outer spacing around the entire masonry grid container.                                   |
| `Allow Scroll`       | When `true`, the grid can be scrolled by the user. When `false`, scrolling is disabled.            |
| `Shrink Wrap`        | If `true`, the grid sizes itself to fit its children instead of expanding to fill available space. |
| `Controller`         | Optional Scroll Controller variable used to programmatically control the scroll position.          |
| `Scroll Direction`   | Defines the axis along which the grid scrolls, typically vertical for masonry layouts.             |

### Controller Integration

The **Controller** property allows you to programmatically control the Masonry Grid’s scroll behavior using a **Scroll Controller** variable.

#### How to Use a Scroll Controller

1. **Create a Scroll Controller Variable**
   * Go to **Variables**.
   * Add a new variable of type **Scroll Controller**.
   * Name it, e.g. `masonryScrollController`.
2. **Bind the Controller to Masonry Grid**
   * Select the Masonry Grid widget.
   * In the **Controller** property, set:\
     `${masonryScrollController}`
3. **Control Scroll Position**
   * Use the **Control Object** action to call methods on the controller:
     * `jumpTo(...)`
     * `animateTo(...)`
     * And other supported scroll methods

For complete details on controller methods, see the **Variables documentation**.

{% hint style="info" %}
**Tip:**

The same controller can be used for:

* Programmatic scrolling
* Scroll-driven animations (e.g. fade on scroll, parallax) via Animation Builder.
  {% endhint %}

### Default Properties

The Masonry Grid widget supports all [Default Properties](/ui-building-blocks/widgets/default-properties.md).

### Best Practices

* **Use Masonry for uneven heights**\
  Ideal for image galleries, cards with varying text length, and content feeds.
* **Choose Cross Axis Count carefully**
  * 2 or 3 columns for mobile
  * More columns for tablets and larger screens
* **Control item height via child**\
  Use aspect-ratio, images, or content length to define the natural height of each card.
* **Handle empty states**\
  If the Data Source is empty, show a separate empty state message or placeholder.
* **Avoid heavy layouts per item**\
  Keep your tile/card template lightweight for smooth scrolling.
* **Use spacing wisely**\
  Add enough spacing to keep the grid readable, especially with text-heavy cards.
* **Avoid nested scrolls in same direction**\
  Don’t put a vertical Masonry Grid inside another vertical scroll unless necessary and handled carefully.
