Using Masonry.js in Nuxt

Jake Peterson
4 min readApr 21, 2018

--

A Masonry grid on jake101.com

David Desandro’s Masonry is everything you’d want in a Javascript library. It performs UI grid magic with all the options you’d ever want. It works with jQuery, vanilla Javascript, and there are a few Vue.js wrappers available for it. Unfortunately, none of them worked for me on my new portfolio website.

Nuxt.js: Universal Javascript Apps for Everyone

Inspired by Zeit’s Next.js, Nuxt is a framework built on top of Vue.js for creating universal web apps that run as Single Page Applications, Server Side Rendered, or as a static generated website. It has an opinionated design that gives structure to Vue and abstracts away some of the complexity of how to run your website on a server. Some code runs server-side and some runs client-side. Masonry needs to run client-side and Nuxt has ways to accommodate that.

Installing Masonry

I went ahead and installed Masonry and ImagesLoaded in my Node modules. The Masonry documentation shows how to install it with npm or yarn but not how to import it in your code.

yarn add masonry-layout imagesloaded

No SSR, no problem!

The Nuxt.js documentation shows how to load a plugin and set a NoSSR boolean on it but this didn’t work for me. Nuxt needs a way to know that this script is only loading on the client-side. Their FAQ section has a snippet to use, taking advantage of the process.browser variable and ES5 require syntax instead of ES6 import.

if (process.browser) {
var Masonry = require(“masonry-layout”);
var ImagesLoaded = require(“imagesloaded”);
}

If you are using the scripts on more than one page, then it is smart to add it to your vendor bundle in your nuxt.config.js.

build: {     
vendor: ['external_library']
}

Setting Masonry’s option using Vue’s data object

We need to set up Masonry’s settings and can use our data object in Nuxt to take care of this. All of Masonry’s options are available in the options object.

data() {
return {
selector: ".viewer",
options: {
columnWidth: ".grid-sizer",
percentPosition: true,
gutter: 0,
itemSelector: ".item"
}
};
}

Initializing Masonry in a Vue event emitter

Create a method to load Masonry, I named it loaded(). ImagesLoaded makes sure that all of the images in our grid layout items have loaded before organizing and laying out everything. After Masonry is loaded, a Vue event is emitted with the Masonry function as a payload.

methods: {loaded() {// all images are loadedImagesLoaded(this.selector, () => {this.$emit("masonry-images-loaded");// activate mansonry gridlet masonry = new Masonry(this.selector, this.options);this.$emit("masonry-loaded", masonry);});}...

Next, the method is loaded on the mounted lifecycle hook or when data is changed.

watch: {data() {this.loaded();}},mounted() {this.loaded();},

HTML & CSS Templating

My HTML template code looks something like this, yours may vary. The .viewer class is the Masonry wrapper, .grid-sizer sets the smallest grid width, and .item is each grid item. .box-0 is displayed at twice the width of the other grid items.

<div class="viewer m-2 mt-3 mt-5 m-md-5"><div class="grid-sizer"></div><div v-for="(image, index) in worksingle.Images" :data-index="index" :key="index" :class="`box-${index}`" class="item"><img class="work-thumb" sizes="100vw" :src="image.path"><div v-if="image.meta.title" :style="`color:#${getImgColor(image.meta.asset)};`" class="working-desc small">{{image.meta.title}}</div></div></div>

Finally, some CSS to style the grid layout.

@media only screen and (max-width: 768px) {
.grid-sizer {
width: 100%;
}
.item {
width: 100%;
padding-bottom: 10px;
padding-left: 0px;
}
.box-0 {
width: 100%;
}
}
@media only screen and (min-width: 769px) {.grid-sizer {
width: 33%;
}
.item {
width: 33%;
padding-bottom: 10px;
padding-left: 10px;
}
.box-0 {
width: 66%;
}
}
@media only screen and (min-width: 1200px) {.grid-sizer {
width: 25%;
}
.item {
width: 25%;
padding-bottom: 10px;
padding-left: 10px;
}
.box-0 {
width: 50%;
}
}

Conclusion

Getting Masonry and other Javascript libraries for UI, layout, and animation to work in Nuxt can be a little tricky but using the process.browser variable, ES5 require syntax, and Vue event emitter can help.

Visit my portfolio at jake101.com and comment with any tips or tricks for working with Nuxt.

--

--