Showing Loading & Error States with Vue.js Async Components


While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

Vue’s first-class support for asynchronous components is great, but not everyone is aware of how to show when an async component is loading or has failed to load. So let’s take a look at how to display error or loading components while we’re waiting for an asynchronous component to load.

Getting Started

Start a simple Vue project with vue-cli and the webpack-simple template.

We’ll be using a dynamic import function that Babel doesn’t support by default, so you’ll need to quickly add a small Babel plugin to get the project to build.

# Yarn
$ yarn add babel-plugin-syntax-dynamic-import -D
$ npm install babel-plugin-syntax-dynamic-import --save-dev

Go ahead and edit .babelrc to add that plugin real quick.

  "presets": [
    ["env", { "modules": false }],
  plugins": ["syntax-dynamic-import"]

Writing the Components

Now let’s go ahead and create three very complex components next to App.vue.

AsyncComponent.vue is what we’ll be loading asynchonously.

  <p>Ohai! I'm an asynchronously-loaded component!</p>

AsyncLoadError.vue is what we’ll display if something goes terribly wrong.

  <p>Oh noes! I was unable to load the asynchronous component. Cry face. :'(</p>

AsyncLoading.vue will display while AsyncComponent.vue is loading.

  <p><em>Loading noises</em></p>

Async Loading

Now, in App.vue, load the utility components as normal, but use the dynanmic import() syntax for AsyncComponent.vue. This function returns a promise that resolves with the actual data when the network request finished.

Then, register AsyncComponent using an arrow function that returns a configuration object. This object specifies what components to use for loading and error states, and how long to wait before considering the component as having failed to load.

You should now be able to use <async-component></async-component> in your app!

  <div id="app">
    <img src="./assets/logo.png">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
      <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
      <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
      <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
      <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>


import AsyncLoadError from './AsyncLoadError.vue'
import AsyncLoading from './AsyncLoading.vue'
const AsyncComponent = import('./AsyncComponent.vue')

export default {
  components: {
    AsyncComponent: () => ({
      // The component we want to load.
      component: AsyncComponent,
      // The component to use as a placeholder while the
      // async component is loading.
      loading: AsyncLoading,
      // The component to render instead if there is an error
      // loading the async component.
      error: AsyncLoadError,
      // The delay before the loading component is shown.
      delay: 100,
      // If this timeout is reached, the async component is considered
      // to have failed loading.
      timeout: 3000

  name: 'app',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'

If you open your browser’s developer tools, you should notice that the asynchronous component is loaded from a different file from the rest of your app. You probably won’t notice the loading and error states unless something goes wrong or you have a very slow network connection, but they will work as well.

TIP: You can test the error state by setting timeout to 0 in the async component configuration object.

That should be all you need!

Creative Commons License