Loaders or spinners are popular way to fill empty container while its content is loading asynchronously. We use it – typically – when some content is loading, by using ajax request or something is processing in the background. We can use loading spinner in VueJS as a separate component in very nice and clean manner by using VueJS functionality – like components, lifecycle hooks and props. With that we can build reusable loading spinner component which will work in the same manner always when we need to do e.g. async request for content
Table of Contents
VueJS demo example for spinner usage
Just for your information – I started in my example VueJS project directly from Vue CLI.
In this article we will create a “Loader-spinner” component in Vue with demo app like in frame below. Click there on “REFRESH DATA” to see loading spinner component.
Click “Refresh data” button to see loading spinner Vue component again.
Create Vue loading spinner component
First thing here is to create a new VueJS component for a spinner. This will be very small component. As we are using Vue CLI, then of course, we use single component files with .vue
extension (Single File Component), so there is HTML (template), JavaScript and CSS code inside one file.
<template> <div v-if="active" class="loader-wrapper"> <div class="loader"> <div></div> <div></div> <div></div> <div></div> </div> <p>{{ text }}</p> </div> </template> <script> export default { name: 'Loader', props: { active: Boolean, text: String } } </script> <style scoped> p { font-size: 0.8em; font-weight: 300; margin-top: 5px; letter-spacing: 1px; color: rgb(82, 82, 82); } .loader-wrapper { text-align: center; } .loader { display: inline-block; position: relative; width: 80px; height: 80px; } .loader div { box-sizing: border-box; display: block; position: absolute; width: 64px; height: 64px; margin: 8px; border: 8px solid #6916a0; border-radius: 50%; animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: #6916a0 transparent transparent transparent; } .loader div:nth-child(1) { animation-delay: -0.45s; } .loader div:nth-child(2) { animation-delay: -0.3s; } .loader div:nth-child(3) { animation-delay: -0.15s; } @keyframes loader { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style>
Let’s check code above step by step:
- The most important thing here is the
v-if="active"
statement. Theactive
variable is a props received from parent (hosting) component, which tells loader to show or hide.
The second prop used here ismessage
– this text also has v-if statement, so it is visible only in message is provided by the parent component. - Spinner component JavaScript code is very simple – it contains only name of component and props definition.
- We use here a loading spinner as CSS animation, so the CSS code is more advanced, but more or less – this is a normal CSS animation, you can find it a lot on the internet.
And loader component code in parent component is as following:
<loader :active="loaderActive" message="Please wait 5 seconds" />
Where loaderActive
variable is passed as :active
prop – so change true/false of loaderActive from parent Vue component, manages visibility of loader.
How to use loading spinner VueJS component
To show you how to use loading component I have created very basic Vue CLI app. Long story short:
This app simulate ajax request to get employees list from the server.
When application is waiting for the server response – the loading spinner is displayed. When employees list is downloaded – the table is visible. There is also a button to refresh employees list download simulation.
What are the most important things in using loader in optimized and clean way? – Let’s go step by step by key features of my vue-loader-spinner demo app:
- Move whole loader functionality into VueJS mixins – mixin something like a part of component shared between many components. Read more here in docs.
export default { data: () => { return { loaderActive: false, } }, methods: { showLoader () { this.loaderActive = true; }, hideLoader () { this.loaderActive = false; }, } }
- In main component of demo VueJS app
App.vue
we have basic functionality:
– loading spinner triggered byloaderActive
variable (from mixin)
– container with refresh data button and the table with employees list. It’s visibility is turned when employees data is insideemployees
array. - In JavaScript code we import first all needed external files and declare Vue component with our mixin import, methods definitions and mounted VueJS lifecycle hook. What is important now and what is the right approach:
– if the data (employees table) must load just after page is opened, then request must start just when component is built, somounted
hook is the best choice. There we runthis.loadData();
method. - We can have also some kind of button which will trigger ajax call on user click (not when page is opened). In our example we have
Refresh data
button. - Data request
loadData()
method must have always – on the beginning – activation of Vue loading spinner component –this.showLoader()
method from mixin, and after data download success or reject – hiding of loader –this.hideLoader()
method from mixin.
Related App.vue code:
<template> <div id="app"> <h1>VueJS loader-spinner</h1> <loader :active="loaderActive" message="Please wait 5 seconds" /> <div v-show="employees.length"> <button @click="refreshData">Refresh data</button> <table> <thead> <tr> <th>index</th> <th>age</th> <th>eyeColor</th> <th>name</th> <th>gender</th> <th>company</th> <th>email</th> <th>phone</th> <th>salary</th> </tr> </thead> <tbody> <tr v-for="row in employees" :key="row.index"> <td>{{row.index}}</td> <td>{{row.age}}</td> <td>{{row.eyeColor}}</td> <td>{{row.name}}</td> <td>{{row.gender}}</td> <td>{{row.company}}</td> <td>{{row.email}}</td> <td>{{row.phone}}</td> <td><input type="number" v-model="row.salary"></td> </tr> </tbody> </table> </div> </div> </template> <script> import Loader from './components/Loader.vue' import { employeesJson } from './mock-data/employees'; import loaderMixin from './mixins/loader'; export default { name: 'App', components: { Loader }, mixins: [loaderMixin], data: () => { return { employees: [] } }, methods: { loadData () { this.showLoader(); setTimeout(() => { this.employees = JSON.parse(employeesJson); this.hideLoader(); }, 5000); }, refreshData () { this.employees = []; this.loadData(); } }, mounted () { this.loadData(); } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; text-align: center; color: #2c3e50; margin-top: 60px; } table { width: 100%; max-width: 1200px; margin: 20px auto; } button { padding: 10px; background: #07ab85; color: #fff; font-weight: bold; border: none; text-transform: uppercase; border-radius: 5px; } </style>
You can check and download whole code of VueJS loading spinner component with the demo app in our GITLAB HERE.