JSFiddle - React, Tailwind, and code Playground

HTML

<masonry-gallery></masonry-gallery>

Babel + JSX

class MasonryGallery extends HTMLElement {

	items = [
    { image:'https://unsplash.it/200/100/' },
    { image:'https://unsplash.it/200/216/' },
    { image:'https://unsplash.it/200/332/' },
    { image:'https://unsplash.it/200/448/' },
    { image:'https://unsplash.it/200/332/' },
    { image:'https://unsplash.it/200/216/' },
    { image:'https://unsplash.it/200/100/' },
    { image:'https://unsplash.it/200/332/' },
    { image:'https://unsplash.it/200/796/' },
    { image:'https://unsplash.it/200/332/' },
    { image:'https://unsplash.it/200/216/' },
    { image:'https://unsplash.it/200/680/' },
    { image:'https://unsplash.it/200/100/' }
  ]

  constructor() {
  	super()
    this.attachShadow({ mode: 'open'})
    this.create()
    this.append()
  }
  
  create() {
  	this.style.display = 'grid'
    this.style.gridTemplateColumns = 'repeat(auto-fill, 200px)'
    this.style.gridAutoRows = '100px'
    this.style.gridGap = '1rem'
    this.style.gridAutoFlow = 'row dense'
  }
  
  append() {
    
    let gap = parseInt(getComputedStyle(this).gridRowGap)
  	
    this.items.map(item => {
    
    	const div = document.createElement('DIV');
      const image = document.createElement('IMG')
      image.style.display = 'block';
      
      image.src = item.image
      div.appendChild(image)
      image.onload = function() {
          this.parentNode.style.gridRow = 'auto / span ' + ((this.height + gap)/(100 + gap));
      }
      
      this.shadowRoot.appendChild(div)
 
    })
    
  }
   
}

customElements.define('masonry-gallery', MasonryGallery)