Eager delay spinners are not a good user experience as they can make a snappy user interface feel slower. We can provide a better user experience (UX) by delaying spinners to appear only after a perceivable delay.
To achieve this improved UX, you can use AsyncComponent.
Vue provides the defineAsyncComponent
function to lazy load components:
1<template>
2 <AsyncComp />
3</template>
4
5<script setup>
6import { defineAsyncComponent } from 'vue'
7
8const AsyncComp = defineAsyncComponent(() => {
9 return new Promise((resolve, reject) => {
10 // ...load component from server
11 resolve(/* loaded component */)
12 })
13})
14</script>
defineAsyncComponent
accepts a loader function that returns a Promise. The resolve
callback should be called if the component has been loaded, and the reject
callback to indicate that loading the component has failed.
Now let's implement the delayed loading spinner by using the advanced options of the defineAsyncComponent
function:
1<template>
2 <AsyncComp />
3</template>
4
5<script>
6import { defineAsyncComponent } from 'vue'
7import Loading from './components/Loading'
8
9export default {
10 components: {
11 AsyncComp: defineAsyncComponent({
12 // the loader function
13 loader: () =>
14 new Promise((resolve) => {
15 setTimeout(() => {
16 resolve(import('./components/HelloWorld.vue'))
17 }, 2000)
18 }),
19
20 // A component to use while the async component is loading
21 loadingComponent: Loading,
22 // Delay before showing the loading component. Default: 200ms.
23 delay: 500,
24 }),
25 },
26 data() {},
27}
28</script>
This demo simulates a network request to fetch HelloWorld.vue
from a server which takes 2 seconds:
1new Promise((resolve) => {
2 setTimeout(() => {
3 resolve(import('./components/HelloWorld.vue'))
4 }, 2000)
5})
The loading component Loading.vue
is shown after a delay of 500ms, defined with delay: 500
.
You can try it yourself in this StackBlitz playground:
If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter:
Vue Tip: Check if Slot Is Empty
You can check if a slot is empty, for example, only to render it if it has content.
Vue Tip: Avoid Empty Wrapper for Conditions
There are many situations when you need to conditionally display multiple Vue components. To avoid "empty" wrappers you should use not use HTML tags.