The use of a Skeleton Layout for asynchronous content is becoming more and more popular across mobile and web apps alike. Google, Facebook, LinkedIn, Youtube and many more use a skeleton layout to display what the content and layout might look like, before it loads. Using one in your own project is a nice styling effect for your users, and also might just improve the SEO of your project in the near future by reducing "cumulative layout shift". This post shows you how easy it is to add a skeleton layout that updates after asynchronous content is loaded.
isLoaded State
React allows for us to set state from isLoaded: false
to isLoaded: true
when an asynchronous function has completed. This will be the basis for which set of content we will display. We will create two CSS classes for our content based on the isLoaded state: .loading
and .loaded
. We will then do an if statement that will return the JSX for the .loaded
content, IF isLoaded = true
. IF isLoaded = false
, the app will return the JSX for the .loading
content, which will be our skeleton layout.
// JSX
class App extends React.Component {
constructor(props){
super(props);
this.state = {
isLoaded: false,
asyncData: []
}
};
render(){
asyncFunction = () => {
// Async function fetches asyncData, and upon fetch updates state from `isLoaded:false` to `isLoaded:true`
}
if(this.state.isLoaded===true){
// If state.isLoaded=true, component will render complete layout and async content
return(
<>
<LayoutContent className="loaded" />
</>
);
}
return(
// While state.isLoaded=false, component will only render skeleton layout
<>
<LayoutContent className="loading" />
</>
);
};
};
CSS
The CSS we need to style will include our two classes: .loading
and .loaded
. This gives you a little freedom for how you would like your skeleton layout to look, but I chose an animated approach from StackFindOver for the styling in the CodePen example below.
// Skeleton Layout styles and animation
.loading {
position: relative;
background: #cccccc;
}
.loading:after {
content: "";
display: block;
position: absolute;
top:0;
width: 100%;
height: 100%;
transform: translateX(-100px);
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
animation: loading 0.8s infinite;
}
@keyframes loading {
100% {
transform: translateX(100%);
}
}
// Loaded styling
.loaded {
// Styles
}
Some additional things to note when it comes to CSS styling:
- Width and Height of components should be defined to reduce content jumping
- Consider using CSS Flexbox for responsive components with max-width/height defined
- If component sizes vary based on content consider adding an "overflow-y: scroll" property
Example Application
Feel free to steal some of the code from this CodePen example, but note you will likely need to adjust some of the styling to fit your own application.
Conclusion
Skeleton layouts not only give your application a fun and useful loading screen as asynchronous content loads, but also might just improve your application's SEO and user experience. Hopefully this blog post and the example gives you some ideas on how to apply a skeleton layout in your own project!
Have you used a Skeleton Layout in your project?
Comment if you have used a similar method, or have suggestions for improvements!
Top comments (11)
Great article! One tip tho - ditch the loading boolean state. There is more than loading/done states. Best approach is to have idle/loading/success/error states. More management is required but, it saves users from waiting despite API call has failed.
This article by Kent is great explanation why:
kentcdodds.com/blog/stop-using-isl...
ahah, I was about to post this, well played.
Actually, his (Kent's) initial structure is not that bad, in his specific case all he needed to do is a) clear position on error or b) move error check higher that position check, i.e. ensuring error's priority
Great tip, I will look into this article! Thanks a ton!!!
I wish people would stop quoting Kent C Dodds.
Why is that?
Great write up. I always wondered how these guys did it but this article really gave me a head start 😊
Awesome sauce! You should be using functional components. Class based components are no longer recommended.
Thanks James, I was thinking that when building the example but wanted to keep this code tutorial accessible to users that may have not made that switch. I might consider transitioning the codepen in the near future.
Great
Nice 👍