<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shuaib hasan akib</title>
    <description>The latest articles on DEV Community by Shuaib hasan akib (@akib).</description>
    <link>https://dev.to/akib</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F641297%2F232c5e2b-e7e2-41ef-9642-eb2aa8c40b45.jpg</url>
      <title>DEV Community: Shuaib hasan akib</title>
      <link>https://dev.to/akib</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akib"/>
    <language>en</language>
    <item>
      <title>Build a masonry grid in Angular</title>
      <dc:creator>Shuaib hasan akib</dc:creator>
      <pubDate>Tue, 06 Oct 2026 04:45:41 +0000</pubDate>
      <link>https://dev.to/akib/build-a-masonry-grid-in-angular-3l16</link>
      <guid>https://dev.to/akib/build-a-masonry-grid-in-angular-3l16</guid>
      <description>&lt;p&gt;Masonry layouts are useful anywhere you have items with different heights but still want a compact, flowing grid.&lt;/p&gt;

&lt;p&gt;Common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Photo and image galleries&lt;/strong&gt; — images naturally have different aspect ratios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboards&lt;/strong&gt; — KPI cards, charts, tables, and widgets rarely have the same height.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product and catalog pages&lt;/strong&gt; — product descriptions and images can vary in size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blog and content feeds&lt;/strong&gt; — cards often contain different amounts of text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio and project grids&lt;/strong&gt; — projects can have very different visual dimensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search and discovery pages&lt;/strong&gt; — results can vary significantly in height.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin and analytics interfaces&lt;/strong&gt; — widgets often have dynamic content and dimensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A normal CSS grid lays items out in rows. If one item is taller than the others, the entire row has to accommodate it, leaving empty space underneath shorter items.&lt;/p&gt;

&lt;p&gt;Masonry solves that by placing each item into the column with the least available height.&lt;/p&gt;

&lt;p&gt;In this guide, we'll build a masonry grid in Angular and gradually add responsive columns, dynamic content, spanning, SSR support, and native CSS masonry.&lt;/p&gt;

&lt;p&gt;By the end, you'll have a grid that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;responds to any screen size&lt;/li&gt;
&lt;li&gt;supports items spanning multiple columns&lt;/li&gt;
&lt;li&gt;automatically reacts to added, removed, or resized items&lt;/li&gt;
&lt;li&gt;avoids layout jumps when images load&lt;/li&gt;
&lt;li&gt;works with Angular SSR&lt;/li&gt;
&lt;li&gt;can use native CSS masonry where available&lt;/li&gt;
&lt;li&gt;has zero runtime dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see the finished result first, check out the &lt;a href="https://masonry-angular.vercel.app/gallery" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use a library?
&lt;/h2&gt;

&lt;p&gt;Before writing JavaScript, it is worth asking whether CSS can already solve the problem.&lt;/p&gt;

&lt;p&gt;There are two common approaches.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS columns
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;column-count&lt;/code&gt; gives you a masonry-like appearance with very little CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.gallery&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;column-count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it fills columns from top to bottom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1  4  7
2  5  8
3  6  9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be problematic when the order of your content matters. A list sorted by date or search relevance no longer reads naturally across the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS Grid
&lt;/h3&gt;

&lt;p&gt;CSS Grid preserves the expected DOM order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.gallery&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it still works in rows. A tall item determines the height of its entire row, leaving empty space underneath shorter items.&lt;/p&gt;

&lt;p&gt;To get both &lt;strong&gt;normal item order&lt;/strong&gt; and &lt;strong&gt;compact masonry packing&lt;/strong&gt;, something needs to measure the items and decide where each one belongs.&lt;/p&gt;

&lt;p&gt;That's the job of &lt;code&gt;masonry-angular&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Native CSS masonry is arriving through &lt;code&gt;display: grid-lanes&lt;/code&gt;. We'll look at that near the end of the article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Install
&lt;/h2&gt;

&lt;p&gt;Install the library with npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;masonry-angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are no additional runtime dependencies.&lt;/p&gt;

&lt;p&gt;The library supports Angular 17.1 and later, including Angular 22.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Build your first grid
&lt;/h2&gt;

&lt;p&gt;Import the masonry directives into your component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NG_MASONRY_GRID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;masonry-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-gallery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;NG_MASONRY_GRID&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;masonry-grid columns="3" gutter="16"&amp;gt;
      @for (photo of photos(); track photo.id) {
        &amp;lt;article masonryGridItem&amp;gt;
          &amp;lt;img
            [src]="photo.url"
            [alt]="photo.title"
          /&amp;gt;

          &amp;lt;h3&amp;gt;{{ photo.title }}&amp;lt;/h3&amp;gt;
        &amp;lt;/article&amp;gt;
      }
    &amp;lt;/masonry-grid&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Gallery&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;photos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://picsum.photos/id/10/400/300&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Forest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://picsum.photos/id/20/400/520&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Desk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://picsum.photos/id/30/400/260&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coffee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://picsum.photos/id/40/400/440&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Street&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two important pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;masonry-grid&amp;gt;&lt;/code&gt; is the container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;masonryGridItem&lt;/code&gt; identifies each child as an item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;columns="3"&lt;/code&gt; creates three columns, while &lt;code&gt;gutter="16"&lt;/code&gt; adds a 16px gap.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NG_MASONRY_GRID&lt;/code&gt; exports the directives needed by the library, so you can import them together.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're using Angular 17 or 18, add &lt;code&gt;standalone: true&lt;/code&gt; to the component metadata.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Don't set the item width
&lt;/h3&gt;

&lt;p&gt;The grid calculates item widths itself.&lt;/p&gt;

&lt;p&gt;Avoid doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.masonry-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A manually assigned width fights the layout engine and can cause overlapping or incorrect positioning.&lt;/p&gt;

&lt;p&gt;You can style everything else normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;masonryGridItem&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let the grid own the width.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make it responsive
&lt;/h2&gt;

&lt;p&gt;A fixed column count isn't ideal across different screen sizes.&lt;/p&gt;

&lt;p&gt;Instead of manually writing breakpoints, you can use &lt;code&gt;columnWidth&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt; &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"260"&lt;/span&gt; &lt;span class="na"&gt;gutter=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make columns approximately 260px wide and fit as many as possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the same grid might automatically become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Desktop:  5 columns
Tablet:   3 columns
Mobile:   1 column
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to maintain a breakpoint table.&lt;/p&gt;

&lt;p&gt;If you need exact column counts, you can define them explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt;
  &lt;span class="na"&gt;[columns]=&lt;/span&gt;&lt;span class="s"&gt;"{
    '0': 1,
    '768': 2,
    '1200': 4
  }"&lt;/span&gt;
  &lt;span class="na"&gt;gutter=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 column from &lt;code&gt;0px&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;2 columns from &lt;code&gt;768px&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;4 columns from &lt;code&gt;1200px&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use named breakpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt; &lt;span class="na"&gt;[columns]=&lt;/span&gt;&lt;span class="s"&gt;"{ xs: 1, md: 2, xl: 4 }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Prevent layout jumps when images load
&lt;/h2&gt;

&lt;p&gt;Masonry layouts are particularly sensitive to image dimensions.&lt;/p&gt;

&lt;p&gt;Imagine the following sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The grid renders.&lt;/li&gt;
&lt;li&gt;Images haven't loaded yet.&lt;/li&gt;
&lt;li&gt;Items are measured at a small height.&lt;/li&gt;
&lt;li&gt;Images download.&lt;/li&gt;
&lt;li&gt;Items suddenly become taller.&lt;/li&gt;
&lt;li&gt;The grid has to rearrange everything.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a visible layout shift.&lt;/p&gt;

&lt;p&gt;The simplest solution is to tell the browser the image dimensions up front:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;[src]=&lt;/span&gt;&lt;span class="s"&gt;"photo.url"&lt;/span&gt;
  &lt;span class="na"&gt;[alt]=&lt;/span&gt;&lt;span class="s"&gt;"photo.title"&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"300"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These attributes establish the image's aspect ratio before the image downloads.&lt;/p&gt;

&lt;p&gt;You can still use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your API already provides image dimensions, use those values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;[src]=&lt;/span&gt;&lt;span class="s"&gt;"photo.url"&lt;/span&gt;
  &lt;span class="na"&gt;[alt]=&lt;/span&gt;&lt;span class="s"&gt;"photo.title"&lt;/span&gt;
  &lt;span class="na"&gt;[width]=&lt;/span&gt;&lt;span class="s"&gt;"photo.width"&lt;/span&gt;
  &lt;span class="na"&gt;[height]=&lt;/span&gt;&lt;span class="s"&gt;"photo.height"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For content where the dimensions are genuinely unknown, use an appropriate CSS &lt;code&gt;aspect-ratio&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The goal is simple: &lt;strong&gt;reserve the space before the content arrives.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Span multiple columns
&lt;/h2&gt;

&lt;p&gt;Sometimes a particular item needs more space.&lt;/p&gt;

&lt;p&gt;For example, a featured photo can span two columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt;
  &lt;span class="na"&gt;masonryGridItem&lt;/span&gt;
  &lt;span class="na"&gt;[masonryColSpan]=&lt;/span&gt;&lt;span class="s"&gt;"photo.featured ? 2 : 1"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;masonryColSpan&lt;/code&gt; rather than trying to increase the CSS width.&lt;/p&gt;

&lt;p&gt;The grid needs to know that the item occupies two columns so it can correctly pack the other items around it.&lt;/p&gt;

&lt;p&gt;If the viewport only has one column, a span of &lt;code&gt;2&lt;/code&gt; is automatically clamped so the item doesn't overflow.&lt;/p&gt;

&lt;p&gt;You can also temporarily remove an item from the layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt;
  &lt;span class="na"&gt;masonryGridItem&lt;/span&gt;
  &lt;span class="na"&gt;[masonryIgnore]=&lt;/span&gt;&lt;span class="s"&gt;"photo.hidden"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The element remains in the DOM, but the masonry engine ignores it.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Let items flow around a fixed element
&lt;/h2&gt;

&lt;p&gt;Another useful pattern is a pinned element that other items should flow around.&lt;/p&gt;

&lt;p&gt;For example, you might have a promotional card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt; &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"260"&lt;/span&gt; &lt;span class="na"&gt;gutter=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;masonryGridStamp&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"promo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Get the weekly digest&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;

  @for (photo of photos(); track photo.id) {
    &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;masonryGridItem&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
  }

&lt;span class="nt"&gt;&amp;lt;/masonry-grid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A stamp can be positioned using CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.promo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;280px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The grid takes the stamp's position into account and packs normal items around it.&lt;/p&gt;

&lt;p&gt;This is useful for ads, promotional cards, subscription boxes, or other fixed content inside a masonry layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Dynamic updates just work
&lt;/h2&gt;

&lt;p&gt;One of the goals of the library is to make dynamic Angular applications feel natural.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;addPhoto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;photos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;photos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;photos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;newPhoto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;You don't need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;reloadItems&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need a &lt;code&gt;setTimeout()&lt;/code&gt; to wait for the DOM.&lt;/p&gt;

&lt;p&gt;The grid observes its children and automatically reflows when items are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;added&lt;/li&gt;
&lt;li&gt;removed&lt;/li&gt;
&lt;li&gt;reordered&lt;/li&gt;
&lt;li&gt;resized&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially useful for Angular applications where the content is controlled by signals, API responses, filtering, or conditional templates.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;visiblePhotos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;photos&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;photo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;photo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the signal changes, the masonry layout follows the DOM.&lt;/p&gt;

&lt;p&gt;You can also listen for completed layout passes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt;
  &lt;span class="na"&gt;(layoutComplete)=&lt;/span&gt;&lt;span class="s"&gt;"onLayout($event)"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;onLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MasonryLayoutEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the grid exposes state through a signal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt;
  &lt;span class="na"&gt;#grid&lt;/span&gt;&lt;span class="err"&gt;="&lt;/span&gt;&lt;span class="na"&gt;masonryGrid&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"260"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/masonry-grid&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  {{ grid.state().columns }} columns,
  {{ grid.state().itemCount }} items
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. SSR without breaking the first render
&lt;/h2&gt;

&lt;p&gt;Masonry libraries often depend on browser APIs such as &lt;code&gt;window&lt;/code&gt; and &lt;code&gt;ResizeObserver&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those APIs don't exist on the server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;masonry-angular&lt;/code&gt; handles this by rendering a CSS-columns fallback during SSR.&lt;/p&gt;

&lt;p&gt;The server can therefore produce usable HTML without needing to measure the items.&lt;/p&gt;

&lt;p&gt;When the browser loads the application, the library switches to the actual masonry layout.&lt;/p&gt;

&lt;p&gt;You can control the server fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt;
  &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"260"&lt;/span&gt;
  &lt;span class="na"&gt;[options]=&lt;/span&gt;&lt;span class="s"&gt;"{
    ssr: {
      fallback: 'columns',
      columns: 2
    }
  }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The common layout settings such as &lt;code&gt;columns&lt;/code&gt;, &lt;code&gt;columnWidth&lt;/code&gt;, &lt;code&gt;gutter&lt;/code&gt;, &lt;code&gt;gutterX&lt;/code&gt;, and &lt;code&gt;gutterY&lt;/code&gt; can be provided directly. More advanced configuration lives under &lt;code&gt;options&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This also makes the component suitable for prerendered Angular applications, where the generated HTML can be served without running a JavaScript masonry engine on the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Use native CSS masonry where available
&lt;/h2&gt;

&lt;p&gt;CSS masonry is moving into the platform through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;display&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;grid-lanes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When native masonry is available, there's little reason to run a JavaScript layout engine.&lt;/p&gt;

&lt;p&gt;You can opt into native support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt;
  &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"260"&lt;/span&gt;
  &lt;span class="na"&gt;gutter=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;
  &lt;span class="na"&gt;[options]=&lt;/span&gt;&lt;span class="s"&gt;"{ native: true }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The library uses native CSS masonry where supported and falls back to its JavaScript layout engine elsewhere.&lt;/p&gt;

&lt;p&gt;That gives you a useful progressive-enhancement model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Native masonry available
        ↓
   Browser handles it

Native masonry unavailable
        ↓
   JS layout engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one important trade-off: when native layout takes over, features that depend on the JavaScript packing algorithm, such as stamps and &lt;code&gt;masonryIgnore&lt;/code&gt;, aren't available.&lt;/p&gt;

&lt;p&gt;If you need those features, keep native mode disabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Set defaults globally
&lt;/h2&gt;

&lt;p&gt;If every masonry grid in your application uses the same defaults, configure them once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideNgMasonryGrid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;masonry-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideNgMasonryGrid&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;gutter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;native&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Individual grids can still override these values when necessary.&lt;/p&gt;

&lt;p&gt;This is particularly useful for design-system or dashboard applications where masonry configuration is consistent throughout the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Masonry for dashboards
&lt;/h2&gt;

&lt;p&gt;Everything above also applies to dashboards.&lt;/p&gt;

&lt;p&gt;Instead of photos, your items might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KPI cards&lt;/li&gt;
&lt;li&gt;charts&lt;/li&gt;
&lt;li&gt;tables&lt;/li&gt;
&lt;li&gt;activity feeds&lt;/li&gt;
&lt;li&gt;statistics&lt;/li&gt;
&lt;li&gt;notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;masonry-grid&lt;/span&gt; &lt;span class="na"&gt;columnWidth=&lt;/span&gt;&lt;span class="s"&gt;"320"&lt;/span&gt; &lt;span class="na"&gt;gutter=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  @for (card of visibleCards(); track card.id) {
    &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt;
      &lt;span class="na"&gt;masonryGridItem&lt;/span&gt;
      &lt;span class="na"&gt;[masonryColSpan]=&lt;/span&gt;&lt;span class="s"&gt;"card.wide ? 2 : 1"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;{{ card.title }}&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;my-chart&lt;/span&gt; &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"card.data"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
  }

&lt;span class="nt"&gt;&amp;lt;/masonry-grid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Don't force every card to the same height
&lt;/h3&gt;

&lt;p&gt;Avoid arbitrary fixed heights when the content is naturally variable.&lt;/p&gt;

&lt;p&gt;Let the card determine its height, and let masonry pack the next item underneath it.&lt;/p&gt;

&lt;p&gt;For charts that render asynchronously, however, you should reserve their expected space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.chart&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;220px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* or */&lt;/span&gt;
  &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents the grid from laying out against a zero-height chart and then moving everything when the chart finally renders.&lt;/p&gt;

&lt;p&gt;The same principle applies to lazy-loaded content such as Angular's &lt;code&gt;@defer&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filtering and reordering
&lt;/h3&gt;

&lt;p&gt;Dashboard layouts are often dynamic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;visibleCards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When cards are filtered, reordered, added, or removed, the grid automatically recalculates the layout.&lt;/p&gt;

&lt;p&gt;You don't need to manually synchronize the masonry engine with your application state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things to remember
&lt;/h2&gt;

&lt;p&gt;If you only remember three things from this article, make them these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't set an item's width.&lt;/strong&gt; The masonry grid owns it. Use &lt;code&gt;masonryColSpan&lt;/code&gt; when an item needs more space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserve space for asynchronous content.&lt;/strong&gt; Give images dimensions and charts an expected height or aspect ratio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't manually trigger layouts.&lt;/strong&gt; Change your Angular state and let the grid react to the DOM.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;masonry-angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://masonry-angular.vercel.app" rel="noopener noreferrer"&gt;https://masonry-angular.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StackBlitz:&lt;/strong&gt; &lt;a href="https://stackblitz.com/github/MeAkib/masonry-angular/tree/main/examples/stackblitz" rel="noopener noreferrer"&gt;https://stackblitz.com/github/MeAkib/masonry-angular/tree/main/examples/stackblitz&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/masonry-angular" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/masonry-angular&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MeAkib/masonry-angular" rel="noopener noreferrer"&gt;https://github.com/MeAkib/masonry-angular&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; &lt;a href="https://github.com/MeAkib/masonry-angular/blob/main/projects/masonry-angular/DOCS.md" rel="noopener noreferrer"&gt;https://github.com/MeAkib/masonry-angular/blob/main/projects/masonry-angular/DOCS.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;masonry-angular&lt;/code&gt; is still early in its development, so the API may evolve.&lt;/p&gt;

&lt;p&gt;If you try it and something feels harder than it should, open an issue or start a discussion. Real-world feedback is especially useful at this stage.&lt;/p&gt;

&lt;p&gt;The project was created to provide a modern Angular-native masonry solution without requiring a separate masonry engine or runtime dependencies.&lt;/p&gt;




</description>
      <category>angular</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>css</category>
    </item>
    <item>
      <title>Angular, Tailwind CSS, and SCSS Boilerplate.</title>
      <dc:creator>Shuaib hasan akib</dc:creator>
      <pubDate>Mon, 26 Jun 2023 10:52:04 +0000</pubDate>
      <link>https://dev.to/akib/angular-tailwind-css-and-scss-boilerplate-1pl4</link>
      <guid>https://dev.to/akib/angular-tailwind-css-and-scss-boilerplate-1pl4</guid>
      <description>&lt;p&gt;I have to write a lot of CSS as a frontend engineer. As a result, I routinely employ Tailwind CSS and SCSS in my angular project. I have to install Angular with SCSS and then Tailwind CSS every time I begin a new project. then setting it up is my common responsibility. So I created a simple boilerplate.  &lt;/p&gt;

&lt;p&gt;Thrilled to introduce open-source Angular, Tailwind CSS, and SCSS boilerplate. Designed to streamline frontend development process and enhance productivity. It can be extend easily. &lt;/p&gt;

&lt;p&gt;Anyone who wants to utilize may do so. Please let me know if you have any suggestions for improvements. I'll make an effort to do that and you'll be appreciated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/akib1997/angular-tailwindcss-scss-boilerplate" rel="noopener noreferrer"&gt;https://github.com/akib1997/angular-tailwindcss-scss-boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>tailwindcss</category>
      <category>scss</category>
      <category>boilerplate</category>
    </item>
  </channel>
</rss>
