avatarEmil Hein

Summary

The webpage provides an overview of creating a spinner component in Vue 3, explaining its purpose, design, and implementation to enhance user experience during data loading.

Abstract

Spinners, also known as loaders, are essential UI elements that indicate to users that a system is actively processing data in the background. The article discusses the importance of spinners in Vue 3 applications to maintain user engagement while waiting for content to load. It provides a basic example of a spinner component using SVG animation, demonstrating how to import and conditionally display it in a Vue application based on the loading state. The article also contrasts the user experience before and after the implementation of a spinner, emphasizing the improvement in perceived performance and trust. Additionally, it offers resources for further learning about transitions and dynamic components in Vue 3, and it concludes by inviting readers to engage with the In Plain English community.

Opinions

  • Spinners are considered a "design trick" to keep users on a site by visually communicating that the system is working, not broken.
  • The author suggests that spinners, despite being a small detail, are crucial for maintaining user trust and improving the overall user experience.
  • The article implies that developers might overlook the importance of spinners, but they are an integral part of a web application's responsiveness.
  • The author provides a subjective assessment that the implementation of a spinner significantly enhances the user experience by providing visual feedback during data fetching.
  • The conclusion reiterates the value of spinners as a visual cue that something is happening, highlighting the author's view on the significance of such UI elements.

Vue 3 — Spinner Component

How and why do we need spinners? And how can we create them in Vue 3?

Loading image

We see them everywhere on every website (almost) we visit. A visual indicator, showing that that the system is doing something. It could look something like this.

And that's all it is. It’s a design “trick”, to keep the users on your site while data is being fetched in the background. It’s meant to communicate that the system is not broken, but simply waiting for something to display the data you need.

Its also sometimes referred to as a loader, even though that word would confuse some people

Why?

These spinners/loaders are necessary to let the user know that something is actually happening. If you don't have these components in your system, some users will end up leaving your site while you are fetching the data.

Example

All frameworks will have different ways of implementing this, but the general idea is the same. We are going to need a component that does the actual visual work of the spinner + a way to decide whether or not that component should be shown.

A basic component could look like this:

<script setup>

</script>

<template>
    <div class="showbox">
        <div class="loader">
            <svg class="circular" viewBox="25 25 50 50">
                <circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10" />
            </svg>
        </div>
    </div>
</template>

<style scoped>
.loader {
    position: relative;
    margin: 0 auto;
    width: 100px;
}

.loader:before {
    content: "";
    display: block;
    padding-top: 100%;
}

.circular {
    -webkit-animation: rotate 2s linear infinite;
    animation: rotate 2s linear infinite;
    height: 100%;
    transform-origin: center center;
    width: 100%;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
}

.path {
    stroke-dasharray: 1, 200;
    stroke-dashoffset: 0;
    -webkit-animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
    animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;
    stroke-linecap: round;
}

@-webkit-keyframes rotate {
    100% {
        transform: rotate(360deg);
    }
}

@keyframes rotate {
    100% {
        transform: rotate(360deg);
    }
}

@-webkit-keyframes dash {
    0% {
        stroke-dasharray: 1, 200;
        stroke-dashoffset: 0;
    }

    50% {
        stroke-dasharray: 89, 200;
        stroke-dashoffset: -35px;
    }

    100% {
        stroke-dasharray: 89, 200;
        stroke-dashoffset: -124px;
    }
}

@keyframes dash {
    0% {
        stroke-dasharray: 1, 200;
        stroke-dashoffset: 0;
    }

    50% {
        stroke-dasharray: 89, 200;
        stroke-dashoffset: -35px;
    }

    100% {
        stroke-dasharray: 89, 200;
        stroke-dashoffset: -124px;
    }
}

@-webkit-keyframes color {

    100%,
    0% {
        stroke: #d62d20;
    }

    40% {
        stroke: #0057e7;
    }

    66% {
        stroke: #008744;
    }

    80%,
    90% {
        stroke: #ffa700;
    }
}

@keyframes color {

    100%,
    0% {
        stroke: #d62d20;
    }

    40% {
        stroke: #0057e7;
    }

    66% {
        stroke: #008744;
    }

    80%,
    90% {
        stroke: #ffa700;
    }
}

body {
    background-color: #eee;
}

.showbox {
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 5%;
}</style>

That will generate something looking like this:

The basic spinner we are going to use

You can easily change this component to be as advanced or as simple as you want to.

Now that we have the component we can freely import it wherever we need it in our application.

I am using a previous example found here, which simply fetches some data from an API. Now we want to show a spinner while we are waiting for the API response.

To use the component in the component showing the blog posts we can do something like this:

<script setup>
import { usePostsStore } from './../stores/posts'
import { useTabStore } from './../stores/tab'
import Spinner from './spinner.vue'
import { computed } from 'vue'

import MediumPreview from './blogDesigns/MediumPreview.vue'
import MediumPreview2 from './blogDesigns/MediumPreview2.vue'

const componentMap = { MediumPreview, MediumPreview2 }
const tabStore = useTabStore()
const postStore = usePostsStore()
const loading = computed(() => {
  return postStore.posts.length === 0
})
</script>

<template>
  <div class="container">
    <Spinner v-if="loading"></spinner>
    <KeepAlive v-else>
      <Transition  name="translate" mode="out-in" v-for="(post) in postStore.posts" :key="post.title">
        <component :is="componentMap[tabStore.tab]" :post="post" />
      </Transition>
    </KeepAlive>
  </div>
</template>

The mechanism is rather simple:

  1. We import the spinner component
  2. We create a computed value, that will indicate if we are waiting for a response from the API
  3. Depending on the computed value we will either show the spinner or the list of blog posts.

For now, I have left out the case where an error occurs, so in this example we only take the simplest use case into account.

Conclusion

Spinners are nothing but a visual trick. It makes it easier for the user to trust that something is happening. The devil is in the details, and that's why we need it. Is the type of component, that a normal user would be excused for leaving out if he/she was tasked to list all the components in an application.

The result before implementing the spinner is this →

Without spinner

While the result after is this →

With spinner

The full repo can be found here

And the live demo can be seen here

You might also like:

In Plain English 🚀

Thank you for being a part of the In Plain English community! Before you go:

Vuejs
Vue 3
Spinner
JavaScript
UX
Recommended from ReadMedium