Lazy-Load Images In Vue.js with vue-clazy-load

Published on August 20, 2017
Default avatar

By Joshua Bemenderfer

Lazy-Load Images In Vue.js with vue-clazy-load

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Images are a fun part of web development. They look great, and are incredibly important in almost every app or site, but they’re huge and slow. A common technique of late is that of lazy-loading images when they enter the viewport. That saves a lot of time loading your app, and only loads the images you need to see. There are a number of lazy-loading solutions for Vue.js, but my personal favorite at the moment is vue-clazy-load.

It’s basically a dead-simple wrapper with slots that allows you do display a custom image and a custom placeholder. There’s not much else, but it’s incredibly flexible.


Install vue-clazy-load in your Vue.js project.

# Yarn
$ yarn add vue-clazy-load

$ npm install vue-clazy-load --save
main.js (Partial)
import Vue from 'vue';
import App from 'App.vue';
import VueClazyLoad from 'vue-clazy-load';




new Vue({
  el: '#app',
  render: h => h(App)

Since vue-clazy-load uses the brand-new IntersectionObserver API, you’ll probably want a polyfill to support it in most browsers. This one works well, but any polyfill that provides the IntersectionObserver API should work.

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>


Now you can use the <clazy-load><clazy-load> component directly, as shown below.

  <div id="app">
    <!-- The src allows the clazy-load component to know when to display the image. -->
    <clazy-load src="https://baconmockup.com/400/400/">
      <!-- The image slot renders after the image loads. -->
      <img src="https://baconmockup.com/400/400/">
      <!-- The placeholder slot displays while the image is loading. -->
      <div slot="placeholder">
        <!-- You can put any component you want in here. -->

This will get you a basic div that starts loading once the element enters the viewport, displays Loading… until the image loads, then displays the image. Nice and simple!

There are, of course a few props you can pass:

  • src: String (required) - The src of the image to load.
  • tag: String - Which component / element clazy-load will render as. (The default is a boring 'ol div.)
  • element: String - Which element to consider as the viewport. Otherwise the browser viewport is used. (Useful if you have a custom scrolling area.)
  • threshold: Array<Number> || Number - How far into the viewing area the clazy-load component needs to be before the load is started. See MDN for more details.
  • margin: String - A value for the margin that gets applied to the intersection observer.
  • ratio: Number - A value between 0 and 1 that corresponds to the percentage of the element that should be in the viewport before loading happens.
  • crossorigin: “anonymous” or “use-credentials” - An option to help work with CORS for images hosted on a different domain.
  • loadedClass: String, loadingClass: String & errorClass: String - Class name to give to the root element for the different states.

There’s also a single event provided, the load event. Which is, as the name implies, emitted when the image finished loading.

Also of note, you can effectively use any components in the slots, including Vue transition components, as shown below:

  <div id="app">
    <!-- Boom: Free fade transitions. -->
    <clazy-load src="https://baconmockup.com/400/400/">
      <transition name="fade">
        <img src="https://baconmockup.com/400/400/">
      <transition name="fade" slot="placeholder">
        <div slot="placeholder">


.fade-enter, .fade-leave-to {
  opacity: 0;


I can’t think of a much easier way to handle image preloading. If you can, feel free to send us a message! For now though, I believe vue-clazy-load can handle pretty much any lazy-loading situation. Enjoy!

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us

About the authors
Default avatar
Joshua Bemenderfer


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel