Tutorial

How To use Skeleton Screens in React and React Native

React

Introduction

A skeleton screen is a term coined by Luke Wroblewski for describing a user experience pattern for displaying neutral elements while gradually loading content into a container.

This pattern focuses on improving the perceived performance. When compared against a blank screen or a traditional spinner, skeleton screens are seen as shorter in duration.

Motion and linear-gradient animations are perceived to be quicker than motionless or pulsating loading animations. For images, using their dominant colors with placeholder elements can also be effective.

In this article, you will be presented with several solutions for implementing skeleton screens in your React and React Native applications.

Using Skeleton Screens in React

In React, it is possible to achieve a skeleton screen effect with componentDidMount and a linear gradient.

However, instead of implementing your own solution, you may want to consider some of the more robust community options crafted to encourage scalability: react-content-loader, react-skeletor, and react-loading-skeleton.

react-content-loader comes loaded with presets for lists, code, and Facebook-styled and Instagram-styled loading cards. It also allows for custom SVG, elements, and color.

Here is an example of react-content-loader:

import ContentLoader, { Facebook } from 'react-content-loader';

const MyFacebookLoader = () => <Facebook />

const MyLoader = () => (
  <ContentLoader>
    {/* Pure SVG */}
    <rect x="0" y="0" rx="5" ry="5" width="70" height="70" />
    <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
    <rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
  </ContentLoader>
)

Alternatively, react-placeholder and SVG-Skeleton are two other popular out-of-the-box solutions that provide placeholder components and styling.

react-skeletor allows for full customization by providing higher-order components with direct connections to load conditionals.

Here is an example of react-skeletor:

import { createSkeletonProvider, createSkeletonElement } from '@trainline/react-skeletor';

const H1 = createSkeletonElement('h1');
const H2 = createSkeletonElement('h2');

const NameCard = ({ firstName, lastName }) => (
  <div>
    <H1 style={style}>{ firstName }</H1>
    <H2 style={style}>{ lastName }</H2>
  </div>
)

const UserDetailPage = ({ user }) => (
  <div>
    ...
    <NameCard user={user} />
    ...
  </div>
)

export default createSkeletonProvider(
  // Dummy data with a similar shape to the component's data.
  {
    user: {
      firstName: '_____',
      lastName: '_____'
    }
  },

  // Predicate that returns true if the component is in a loading state.
  ({ user }) => user === undefined,

  // Define the placeholder styling for the children elements.
  () => ({
    color: 'grey',
    backgroundColor: 'grey'
  })
)(UserDetailPage)

This blog post goes into further detail on the benefits of using react-skeletor.

react-loading-skeleton automatically creates skeleton screens from the styles themselves, eliminating the need to create dedicated skeleton screen components altogether.

Here is an example of react-loading-skeleton:

import Skeleton from 'react-loading-skeleton';

const Blogpost = () => <div style={{ fontSize: 20, lineHeight: 2 }}>
  <h1>{this.props.title || <Skeleton />}</h1>
  {this.props.body || <Skeleton count={10} />}
</div>

That concludes using skeleton screens in React.

Using Skeleton Screens in React Native

React Native applications can consider two community options: react-native-svg-animated-linear-gradient and react-native-shimmer.

react-native-svg-animated-linear-gradient can created an animated linear gradient effect.

Here is an example of react-native-svg-animated-linear-gradient:

import SvgAnimatedLinearGradient from 'react-native-svg-animated-linear-gradient';

// Instagram style.
<SvgAnimatedLinearGradient height={300}>
    <Circle cx="30" cy="30" r="30"/>
    <Rect x="75" y="13" rx="4" ry="4" width="100" height="13"/>
    <Rect x="75" y="37" rx="4" ry="4" width="50" height="8"/>
    <Rect x="0" y="70" rx="5" ry="5" width="400" height="200"/>
</SvgAnimatedLinearGradient>

react-native-shimmer is a React Native implementation of Facebook’s Shimmer implemented in iOS and Android.

Here is an example of react-native-shimmer:

import Shimmer from 'react-native-shimmer';

<Shimmer>
  <Text>Loading...</Text>
</Shimmer>

That concludes using skeleton screens in React Native.

Exploring Alternatives

Outside React, the JavaScript community has solved this problem as well. Placeload.js is a popular solution. jquery.skeleton.loader is a jQuery plugin.

And Semantic UI has its own built-in Placeholder element.

Using Images and Dominant Color

Instead of creating a shimmer effect with gradients, an image’s dominant color can give guidance and context to the user before the content is loaded.

A few resources on extracting the primary colors from an image: color-thief, node-vibrant, and color-loader.

Conclusion

In this article, you were presented with several solutions for implementing skeleton screens in your React and React Native applications.

This presentation by Luke Wroblewski introduces skeleton screens.

These articles go into detail about using skeleton screens: Everything you need to know about skeleton screens and Stop Using Loading Spinner, There’s Something Better.

Serverside Rendering (SSR) is a big part of managing users’ page load experience. Relevant skeleton screens should be included in the “App Shell” and initial page load. Addy Osmani covers how this works with React.

Accessibility should be a consideration as screen-readers and assistive software can become tripped-up and create confusing experiences when it comes to extra page elements like skeleton screens. Ray Roman suggests using ARIA labeling, like aria-disabled={true} or aria-label="loading", to help ignore these elements.

Before implementing skeleton screens, you may wish to consider the counter-arguments in A Bone to Pick with Skeleton Screens.

Creative Commons License