Image for post
Image for post
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

Image for post
Image for post
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

Image for post
Image for post
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:

Image for post
Image for post
draw.io diagram
Image for post
Image for post
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

Image for post
Image for post

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

Image for post
Image for post

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

Image for post
Image for post
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.

Image for post
Image for post
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

Image for post
Image for post
CardSkeletonMedia.vue

Now our skeleton card looks like this:

Image for post
Image for post
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

Image for post
Image for post
CardSkeletonText

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

Image for post
Image for post
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

Image for post
Image for post
CardSkeletonActions.vue

Finally

Image for post
Image for post
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

Image for post
Image for post
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

Image for post
Image for post
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.

Image for post
Image for post
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

Vue.js Developers

Helping web professionals up their skill and knowledge of…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store