Photo by Robson Hatsukami Morgan on Unsplash. Per aspera ad astra

Async in Vue.js - Part 1

Create a shape shifter Skeleton Card in Vuejs with Vuetify instead of a loader

Problem

Display a loading feedback into a web application is a big thing. A common approach is to just use a spinner loader to notify the user that something is happening.

This method has some drawbacks, for example, it does not say anything about the future content. Therefore the user has no clue of what it is going to be displayed.

Solution

Skeleton screens can be used instead of spinners to provide a stronger feedback

Facebook skeleton screen

You can read more about them here:

and here:

http://blog.iamsuleiman.com/stop-using-loading-spinner-theres-something-better/

Implementation

Fist of all. The code can be found here as well as the instructions to install it

https://github.com/FrancescoSaverioZuppichini/skeleton-card-vuejs

We are going to use Vuejs to build this

A skeleton card

A generic card-based skeleton. A Card is a container for a piece of information.

For this tutorial we will play with Vuetify, a widely used UI framework for Vuejs. You can check it out here:

https://vuetifyjs.com/vuetify/quick-start

Some time ago I developed a library to create Vuejs app from a draw.io diagram called draw.io2vuejs. I will use it to quickly create the project. You can read how it works here:

Let’s create the diagram. A card is composed by four elements, a header, a media, a text and the actions. Similarly, our CardSkeleton sub-graph looks like:

draw.io diagram
drawio2vuejs output

Ready to go!

We first need to create the basic structure inside CardSkeletron . Remember that a card can be horizontal or vertical.

In a vertical card, the header is on the top followed by the media and the content. In a horizontal card, the media is on the right at the same level of the text.

Also, we need to provide an interface, API, in order to change the shape of the card to mimic the content we want to display. This can be archive by passing props to the component as boolean flags:

props: {
'hasHeader': {
default: true
},
'hasMedia': {
default: true
},
'hasText': {
default: true
},
'hasActions': {
default: false
},
'isHorizontal': {
default: false
},
'lines':{
default: 2
}
},

Now we can create a basic template using the custom Vuetify components such as v-card

Depending on the prop isHorizontalwe use a flex row container instead of a column to quickly change the layout.

We now need to actually code the four main components: CardSkeltonHeader, CardSkeltonMedia , CardSkeltonText and CardSkeltonActions

Let’s start with the first one. We use custom css classes to simulate block of words.

<style scoped>
.skeleton-card__header__avatar {
border-radius: 50%;
height: 50px;
width: 50px;
background-color: grey;
}
.skeleton-card__header__subtitle {
width: 70%;
height: 12px;
}
.skeleton-card__header__title {
width: 100%;
height: 14px;
}
</style>

And the template

We are taking advantages from the smart Vuetify’s layout system. The result is the follow

The header

As you may see, the title has a stronger color than the subtitle in order to give it more importance. A card could also have a media that is usually displayed between the header and the text content.

https://material.io/guidelines/components/cards.html#

Open the CardSkeletonMedia component and use the v-card-media component with a custom css class in order to add a grey background

CardSkeletonMedia.vue

Now our skeleton card looks like this:

Header + Media

We are missing the text behind the media, let’s fix it! Open CardSkeletonText and similarly to the header use custom css classes to simulate the content

CardSkeletonText

The lines prop is used to change the amount of text that our card has. Let’s see how it looks like now

Header + Media + Text

Each card usually has some buttons that are used to interact with it, they are called actions . We can simulate them by creating a grey boxes below the text to mime hovered buttons.

In CardSkeletonActions add the following code

CardSkeletonActions.vue

Finally

Full vertical skeleton card

To create a horizontal card, go back in CardSkeleton and add a condition based on the isHorizontal prop in order to change the flex orientation:

//CardSkeleton.vue
...
<v-container v-if="isHorizontal">
<v-layout row align-center>
<v-flex class="flex--grow">
<card-skeleton-text :lines="lines">
</card-skeleton-text>
</v-flex>
<v-flex>
<card-skeleton-media height="150px" width="150px" v-if="hasMedia">
</card-skeleton-media>
</v-flex>
</v-layout>
</v-container>
<v-layout column v-else>
<v-flex>
<card-skeleton-media v-if="hasMedia">
</card-skeleton-media>
</v-flex>
<v-flex>
<card-skeleton-text :lines="lines" v-if="hasText">
</card-skeleton-text>
</v-flex>
</v-layout>
...

Now, if we pass the isHorizontal prop and remove the header

<card-skeleton :isHorizontal="true" :hasHeader="false" :lines="2"> </card-skeleton>

The card will look like this

A horizontal skeleton card

We can play a little bit with the props, for example we may need a horizontal card with actions. In that case, we can set the hasActions prop to true

Horizontal card with actions

Or we may want to have a vertical card with just more text and actions. So set hasHeader and hasMedia to false , hasActions to true and lines to 4.

Vertical card with text and actions

Conclusion

We have seen how to make a reusable skeleton card component that can be used to replace loading spinner to provide a clue of how the content will look like. Also, we have developed a shape-shifter component using props to further customise the component.

In part 2 we are going to see a real life scenario when we will use our newly created component to properly load some cocktails fetched through AJAX requests.

You can read it here:

https://medium.com/@FrancescoZ/async-in-vuejs-part-2-45e81c836e38

If you have any feedbacks, please leave a comment.

Thank you for reading

Francesco Saverio Zuppichini