Masonry

Vue Bootstrap 5 Masonry component

Responsive masonry built with Vue Bootstrap 5. Masonry is a grid layout based on columns & it optimizes the use of space inside the web page by reducing any unnecessary gaps.

To learn more read Docs.


Basic layout

<template>
  <div class="masonry-with-columns" id="masonry-with-columns">
    <div style="order: 0">1</div>
    <div style="order: 1">2</div>
    <div style="order: 2">3</div>
    <div style="order: 0">4</div>
    <div style="order: 1">5</div>
    <div style="order: 2">6</div>
    <div style="order: 0">7</div>
    <div style="order: 1">8</div>
    <div style="order: 2">9</div>
    <div style="order: 0">10</div>
    <div style="order: 1">11</div>
    <div style="order: 2">12</div>
    <div style="order: 0">13</div>
    <div style="order: 1">14</div>
    <div style="order: 2">15</div>
  </div>
</template>
<style>
  body {
    margin: 0;
    padding: 1rem;
  }

  .masonry-with-columns {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -webkit-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-flex-wrap: wrap;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    max-height: 1000px;
  }

  .masonry-with-columns div {
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 auto;
    -ms-flex: 1 0 auto;
    flex: 1 0 auto;
    background: #00997b;
    color: white;
    margin: 0 1rem 1rem 0;
    text-align: center;
    font-weight: 900;
    font-size: 2rem;
  }

  .masonry-with-columns div:nth-child(1) {
    height: 163px;
    line-height: 163px;
  }

  .masonry-with-columns div:nth-child(2) {
    height: 495px;
    line-height: 495px;
  }

  .masonry-with-columns div:nth-child(3) {
    height: 120px;
    line-height: 120px;
  }

  .masonry-with-columns div:nth-child(4) {
    height: 309px;
    line-height: 309px;
  }

  .masonry-with-columns div:nth-child(5) {
    height: 317px;
    line-height: 317px;
  }

  .masonry-with-columns div:nth-child(6) {
    height: 277px;
    line-height: 277px;
  }

  .masonry-with-columns div:nth-child(7) {
    height: 339px;
    line-height: 339px;
  }

  .masonry-with-columns div:nth-child(8) {
    height: 491px;
    line-height: 491px;
  }

  .masonry-with-columns div:nth-child(9) {
    height: 281px;
    line-height: 281px;
  }

  .masonry-with-columns div:nth-child(10) {
    height: 499px;
    line-height: 499px;
  }

  .masonry-with-columns div:nth-child(11) {
    height: 490px;
    line-height: 490px;
  }

  .masonry-with-columns div:nth-child(12) {
    height: 289px;
    line-height: 289px;
  }

  .masonry-with-columns div:nth-child(13) {
    height: 356px;
    line-height: 356px;
  }

  .masonry-with-columns div:nth-child(14) {
    height: 406px;
    line-height: 406px;
  }

  .masonry-with-columns div:nth-child(15) {
    height: 196px;
    line-height: 196px;
  }

  .masonry-with-columns div:nth-child(16) {
    height: 237px;
    line-height: 237px;
  }

  .masonry-with-columns div:nth-child(17) {
    height: 367px;
    line-height: 367px;
  }

  .masonry-with-columns div:nth-child(18) {
    height: 472px;
    line-height: 472px;
  }

  .masonry-with-columns div:nth-child(19) {
    height: 413px;
    line-height: 413px;
  }

  .masonry-with-columns div:nth-child(20) {
    height: 337px;
    line-height: 337px;
  }

  .masonry-with-columns div:nth-child(21) {
    height: 406px;
    line-height: 406px;
  }

  .masonry-with-columns div:nth-child(22) {
    height: 368px;
    line-height: 368px;
  }

  .masonry-with-columns div:nth-child(23) {
    height: 130px;
    line-height: 130px;
  }

  .masonry-with-columns div:nth-child(24) {
    height: 209px;
    line-height: 209px;
  }

  .masonry-with-columns div:nth-child(25) {
    height: 203px;
    line-height: 203px;
  }

  .masonry-with-columns div:nth-child(26) {
    height: 368px;
    line-height: 368px;
  }

  .masonry-with-columns div:nth-child(27) {
    height: 163px;
    line-height: 163px;
  }

  .masonry-with-columns div:nth-child(28) {
    height: 418px;
    line-height: 418px;
  }

  .masonry-with-columns div:nth-child(29) {
    height: 123px;
    line-height: 123px;
  }

  .masonry-with-columns div:nth-child(30) {
    height: 256px;
    line-height: 256px;
  }

  .masonry-with-columns div:nth-child(31) {
    height: 196px;
    line-height: 196px;
  }

  .masonry-with-columns div:nth-child(32) {
    height: 224px;
    line-height: 224px;
  }

  .masonry-with-columns div:nth-child(33) {
    height: 122px;
    line-height: 122px;
  }

  .masonry-with-columns div:nth-child(34) {
    height: 303px;
    line-height: 303px;
  }

  .masonry-with-columns div:nth-child(35) {
    height: 159px;
    line-height: 159px;
  }

  .masonry-with-columns div:nth-child(36) {
    height: 320px;
    line-height: 320px;
  }
</style>
<script>
  import {
    onMounted
  } from "vue";
  export default {
    setup() {
      const masonry = () => {
        const numCols = 3;
        const colHeights = Array(numCols).fill(0);
        const container = document.querySelector("#masonry-with-columns");
        Array.from(container.children).forEach((child, i) => {
          const order = i % numCols;
          child.style.order = order;
          colHeights[order] += parseFloat(child.clientHeight);
        });
        container.style.height = Math.max(...colHeights) + "px";
      };

      onMounted(() => masonry());
    },
  };
</script>

Horizontal option

<template>
  <div class="masonry-with-columns-2" id="masonry-with-columns-2">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>
    <div>10</div>
    <div>11</div>
    <div>12</div>
    <div>13</div>
    <div>14</div>
    <div>15</div>
  </div>
</template>
<style>
  body {
    margin: 0;
    padding: 1rem;
  }

  .masonry-with-columns-2 {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-wrap: wrap;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
  }

  .masonry-with-columns-2 div {
    height: 150px;
    line-height: 150px;
    background: #9b1b30;
    color: white;
    margin: 0 1rem 1rem 0;
    text-align: center;
    font-weight: 900;
    font-size: 2rem;
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 auto;
    -ms-flex: 1 0 auto;
    flex: 1 0 auto;
  }

  .masonry-with-columns-2 div:nth-child(1) {
    width: 222px;
  }

  .masonry-with-columns-2 div:nth-child(2) {
    width: 102px;
  }

  .masonry-with-columns-2 div:nth-child(3) {
    width: 155px;
  }

  .masonry-with-columns-2 div:nth-child(4) {
    width: 365px;
  }

  .masonry-with-columns-2 div:nth-child(5) {
    width: 132px;
  }

  .masonry-with-columns-2 div:nth-child(6) {
    width: 106px;
  }

  .masonry-with-columns-2 div:nth-child(7) {
    width: 199px;
  }

  .masonry-with-columns-2 div:nth-child(8) {
    width: 164px;
  }

  .masonry-with-columns-2 div:nth-child(9) {
    width: 424px;
  }

  .masonry-with-columns-2 div:nth-child(10) {
    width: 467px;
  }

  .masonry-with-columns-2 div:nth-child(11) {
    width: 350px;
  }

  .masonry-with-columns-2 div:nth-child(12) {
    width: 168px;
  }

  .masonry-with-columns-2 div:nth-child(13) {
    width: 296px;
  }

  .masonry-with-columns-2 div:nth-child(14) {
    width: 440px;
  }

  .masonry-with-columns-2 div:nth-child(15) {
    width: 110px;
  }

  .masonry-with-columns-2 div:nth-child(16) {
    width: 413px;
  }

  .masonry-with-columns-2 div:nth-child(17) {
    width: 333px;
  }

  .masonry-with-columns-2 div:nth-child(18) {
    width: 441px;
  }

  .masonry-with-columns-2 div:nth-child(19) {
    width: 74px;
  }

  .masonry-with-columns-2 div:nth-child(20) {
    width: 122px;
  }

  .masonry-with-columns-2 div:nth-child(21) {
    width: 189px;
  }

  .masonry-with-columns-2 div:nth-child(22) {
    width: 91px;
  }

  .masonry-with-columns-2 div:nth-child(23) {
    width: 269px;
  }

  .masonry-with-columns-2 div:nth-child(24) {
    width: 394px;
  }

  .masonry-with-columns-2 div:nth-child(25) {
    width: 139px;
  }

  .masonry-with-columns-2 div:nth-child(26) {
    width: 240px;
  }

  .masonry-with-columns-2 div:nth-child(27) {
    width: 184px;
  }

  .masonry-with-columns-2 div:nth-child(28) {
    width: 261px;
  }

  .masonry-with-columns-2 div:nth-child(29) {
    width: 358px;
  }

  .masonry-with-columns-2 div:nth-child(30) {
    width: 393px;
  }

  .masonry-with-columns-2 div:nth-child(31) {
    width: 370px;
  }

  .masonry-with-columns-2 div:nth-child(32) {
    width: 399px;
  }

  .masonry-with-columns-2 div:nth-child(33) {
    width: 263px;
  }

  .masonry-with-columns-2 div:nth-child(34) {
    width: 135px;
  }

  .masonry-with-columns-2 div:nth-child(35) {
    width: 221px;
  }

  .masonry-with-columns-2 div:nth-child(36) {
    width: 233px;
  }
</style>

Flexbox option

<template>
  <div class="masonry-with-flex">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>
    <div>10</div>
    <div>11</div>
    <div>12</div>
    <div>13</div>
    <div>14</div>
    <div>15</div>
  </div>
</template>
<style>
  body {
    margin: 0;
    padding: 1rem;
  }

  .masonry-with-flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -webkit-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-flex-wrap: wrap;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    max-height: 1000px;
  }

  .masonry-with-flex div {
    width: auto;
    background: #975a58;
    color: white;
    margin: 0 1rem 1rem 0;
    text-align: center;
    font-weight: 900;
    font-size: 2rem;
  }

  .masonry-with-flex div:nth-child(1) {
    height: 334px;
    line-height: 334px;
  }

  .masonry-with-flex div:nth-child(2) {
    height: 428px;
    line-height: 428px;
  }

  .masonry-with-flex div:nth-child(3) {
    height: 432px;
    line-height: 432px;
  }

  .masonry-with-flex div:nth-child(4) {
    height: 292px;
    line-height: 292px;
  }

  .masonry-with-flex div:nth-child(5) {
    height: 312px;
    line-height: 312px;
  }

  .masonry-with-flex div:nth-child(6) {
    height: 191px;
    line-height: 191px;
  }

  .masonry-with-flex div:nth-child(7) {
    height: 302px;
    line-height: 302px;
  }

  .masonry-with-flex div:nth-child(8) {
    height: 224px;
    line-height: 224px;
  }

  .masonry-with-flex div:nth-child(9) {
    height: 475px;
    line-height: 475px;
  }

  .masonry-with-flex div:nth-child(10) {
    height: 440px;
    line-height: 440px;
  }

  .masonry-with-flex div:nth-child(11) {
    height: 426px;
    line-height: 426px;
  }

  .masonry-with-flex div:nth-child(12) {
    height: 362px;
    line-height: 362px;
  }

  .masonry-with-flex div:nth-child(13) {
    height: 129px;
    line-height: 129px;
  }

  .masonry-with-flex div:nth-child(14) {
    height: 344px;
    line-height: 344px;
  }

  .masonry-with-flex div:nth-child(15) {
    height: 236px;
    line-height: 236px;
  }

  .masonry-with-flex div:nth-child(16) {
    height: 378px;
    line-height: 378px;
  }

  .masonry-with-flex div:nth-child(17) {
    height: 312px;
    line-height: 312px;
  }

  .masonry-with-flex div:nth-child(18) {
    height: 172px;
    line-height: 172px;
  }

  .masonry-with-flex div:nth-child(19) {
    height: 474px;
    line-height: 474px;
  }

  .masonry-with-flex div:nth-child(20) {
    height: 252px;
    line-height: 252px;
  }

  .masonry-with-flex div:nth-child(21) {
    height: 355px;
    line-height: 355px;
  }

  .masonry-with-flex div:nth-child(22) {
    height: 401px;
    line-height: 401px;
  }

  .masonry-with-flex div:nth-child(23) {
    height: 369px;
    line-height: 369px;
  }

  .masonry-with-flex div:nth-child(24) {
    height: 449px;
    line-height: 449px;
  }

  .masonry-with-flex div:nth-child(25) {
    height: 411px;
    line-height: 411px;
  }

  .masonry-with-flex div:nth-child(26) {
    height: 122px;
    line-height: 122px;
  }

  .masonry-with-flex div:nth-child(27) {
    height: 262px;
    line-height: 262px;
  }

  .masonry-with-flex div:nth-child(28) {
    height: 154px;
    line-height: 154px;
  }

  .masonry-with-flex div:nth-child(29) {
    height: 308px;
    line-height: 308px;
  }

  .masonry-with-flex div:nth-child(30) {
    height: 327px;
    line-height: 327px;
  }

  .masonry-with-flex div:nth-child(31) {
    height: 374px;
    line-height: 374px;
  }

  .masonry-with-flex div:nth-child(32) {
    height: 106px;
    line-height: 106px;
  }

  .masonry-with-flex div:nth-child(33) {
    height: 340px;
    line-height: 340px;
  }

  .masonry-with-flex div:nth-child(34) {
    height: 492px;
    line-height: 492px;
  }

  .masonry-with-flex div:nth-child(35) {
    height: 475px;
    line-height: 475px;
  }

  .masonry-with-flex div:nth-child(36) {
    height: 373px;
    line-height: 373px;
  }
</style>

Images option

<template>
  <div class="masonry-with-flex masonry-with-columns" style="max-height: 1200px">
    <img src="https://mdbootstrap.com/img/Photos/Others/food3.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image06.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image17.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image02.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image008.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image010.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image002.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image005.webp" style="width: 33.3%" />
    <img src="https://mdbootstrap.com/img/Photos/Others/image18.webp" style="width: 33.3%" />
  </div>
</template>
<style>
  .masonry-with-columns,
  .masonry-with-flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -webkit-flex-direction: column;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-flex-wrap: wrap;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
  }

  .masonry-with-columns div {
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 auto;
    -ms-flex: 1 0 auto;
    flex: 1 0 auto;
  }
</style>
<script>
  import {
    onMounted
  } from "vue";
  export default {
    setup() {
      onMounted(() => {
        const masonryWrapper = document.querySelector(".masonry-with-flex");
        Array.from(masonryWrapper.children).forEach((child, i) => {
          const order = i % 3;
          child.style.order = order;
        });
      });
    },
  };
</script>