Skeleton screens with React and React Native ☠

November 20, 2018 0 Comments

Skeleton screens with React and React Native ☠

 

 

A skeleton screen is a user experience pattern that’s shown to reduce load time frustration. Luke Wroblewski coined this term for displaying neutral elements while gradually loading content into a container. This creates better “perceived performance”, as occupied time feels shorter than unoccupied time.

Youtube Skeleton Screens, Bill Chung (UX Collective)

Perceived performance

Rather than most performance or UX wins, this pattern only focuses on improving the perceived experience. When compared against a blank screen or a traditional spinner, skeleton screens are seen as shorter in duration. Studies are still exploring their effectiveness but, as developers, what options do we have available to handle this?

Best practices

Before diving in, there are some best practices to consider:

  • 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.

  • 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 indepth.

  • 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.

React

In React, a quick-and-dirty form of skeleton screens can be simply achieved with componentDidMount and a linear gradient. This article covers the more robust community options crafted to encourage scalability.

react-content-loader

Best out-of-the-box solution. Comes loaded with presets for lists, code, Facebook, and Instagram styled loading cards. Allows for custom SVG, elements, and color.

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

Most flexible. Allows for full customization by providing higher-order components with direct connections to load conditionals. This blog post documents why that’s awesome.

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 component is in a loading state ({ user }) => user === undefined, // Define the placeholder styling for the children elements, () => ({ color: 'grey', backgroundColor: 'grey' })
)(UserDetailPage)

react-loading-skeleton

Most exciting. Automatically creates skeleton screens from the styles themselves, eliminating the need to create dedicated skeleton screen components all together. Note: As of this writing there’s only support for rectangles.

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>

React Native

When it comes to React Native, there are far less community solutions to pick from.

react-native-svg-animated-linear-gradient

The most widely used solution but, as of this writing, has a dependency on Expo. There is a pull-request open to remove the dependency. Other efforts have moved towards a fork under the name react-native-content-loader, but the current npm package for that links to a non-existant Github repo, so be careful with npm install.

import SvgAnimatedLinearGradient from 'react-native-svg-animated-linear-gradient' //Instagram style 
<SvgAnimatedLinearGradient height={300}> <Svg.Circle cx="30" cy="30" r="30"/> <Svg.Rect x="75" y="13" rx="4" ry="4" width="100" height="13"/> <Svg.Rect x="75" y="37" rx="4" ry="4" width="50" height="8"/> <Svg.Rect x="0" y="70" rx="5" ry="5" width="400" height="200"/>
</SvgAnimatedLinearGradient>

react-native-shimmer

A React Native implementation of Facebook’s Shimmer implemented in iOS and Android.

import Shimmer from 'react-native-shimmer' <Shimmer> <Text>Loading...</Text> 
</Shimmer>

Alternatives

Outside React, the JS community has solved this problem as well. Placeload.js is a popular vanilla solution, jquery.skeleton.loader is a jQuery plugin, and Semantic UI has its own built-in Placeholder element.

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. Here are a few resources on extracting the primary colors from an image.

Further Reading:


Tag cloud