Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

react-loading-skeleton

dvtng3.7mMIT3.5.0TypeScript support: included

Make beautiful, animated loading skeletons that automatically adapt to your app.

react, loading, skeleton, progress, spinner

readme

Logo

React Loading Skeleton

Make beautiful, animated loading skeletons that automatically adapt to your app.

Open on CodeSandbox

Gif of the skeleton in action

Learn about the changes in version 3, or view the v2 documentation.

Basic Usage

Install via one of:

yarn add react-loading-skeleton
npm install react-loading-skeleton
import Skeleton from 'react-loading-skeleton'
import 'react-loading-skeleton/dist/skeleton.css'

<Skeleton /> // Simple, single-line loading skeleton
<Skeleton count={5} /> // Five-line loading skeleton

Principles

Adapts to the styles you have defined

The Skeleton component should be used directly in your components in place of content that is loading. While other libraries require you to meticulously craft a skeleton screen that matches the font size, line height, and margins of your content, the Skeleton component is automatically sized to the correct dimensions.

For example:

function BlogPost(props) {
  return (
    <div>
      <h1>{props.title || <Skeleton />}</h1>
      {props.body || <Skeleton count={10} />}
    </div>
  );
}

...will produce correctly-sized skeletons for the heading and body without any further configuration.

This ensures the loading state remains up-to-date with any changes to your layout or typography.

Don't make dedicated skeleton screens

Instead, make components with built-in skeleton states.

This approach is beneficial because:

  1. It keeps styles in sync.
  2. Components should represent all possible states — loading included.
  3. It allows for more flexible loading patterns. In the blog post example above, it's possible to have the title load before the body, while having both pieces of content show loading skeletons at the right time.

Theming

Customize individual skeletons with props, or render a SkeletonTheme to style all skeletons below it in the React hierarchy:

import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';

return (
  <SkeletonTheme baseColor="#202020" highlightColor="#444">
    <p>
      <Skeleton count={3} />
    </p>
  </SkeletonTheme>
);

Props Reference

Skeleton only

Prop Description Default
count?: number The number of lines of skeletons to render. If count is a decimal number like 3.5, three full skeletons and one half-width skeleton will be rendered. 1
wrapper?: React.FunctionComponent
<PropsWithChildren<unknown>>
A custom wrapper component that goes around the individual skeleton elements.
circle?: boolean Makes the skeleton circular by setting border-radius to 50%. false
className?: string A custom class name for the individual skeleton elements which is used alongside the default class, react-loading-skeleton.
containerClassName?: string A custom class name for the <span> that wraps the individual skeleton elements.
containerTestId?: string A string that is added to the container element as a data-testid attribute. Use it with screen.getByTestId('...') from React Testing Library.
style?: React.CSSProperties This is an escape hatch for advanced use cases and is not the preferred way to style the skeleton. Props (e.g. width, borderRadius) take priority over this style object.

Skeleton and SkeletonTheme

Prop Description Default
baseColor?: string The background color of the skeleton. #ebebeb
highlightColor?: string The highlight color in the skeleton animation. #f5f5f5
width?: string | number The width of the skeleton. 100%
height?: string | number The height of each skeleton line. The font size
borderRadius?: string | number The border radius of the skeleton. 0.25rem
inline?: boolean By default, a <br /> is inserted after each skeleton so that each skeleton gets its own line. When inline is true, no line breaks are inserted. false
duration?: number The length of the animation in seconds. 1.5
direction?: 'ltr' | 'rtl' The direction of the animation, either left-to-right or right-to-left. 'ltr'
enableAnimation?: boolean Whether the animation should play. The skeleton will be a solid color when this is false. You could use this prop to stop the animation if an error occurs. true
customHighlightBackground?: string Allows you to override the background-image property of the highlight element, enabling you to fully customize the gradient. See example below. undefined

Examples

Custom Wrapper

There are two ways to wrap a skeleton in a container:

function Box({ children }: PropsWithChildren<unknown>) {
  return (
    <div
      style={{
        border: '1px solid #ccc',
        display: 'block',
        lineHeight: 2,
        padding: '1rem',
        marginBottom: '0.5rem',
        width: 100,
      }}
    >
      {children}
    </div>
  );
}

// Method 1: Use the wrapper prop
const wrapped1 = <Skeleton wrapper={Box} count={5} />;

// Method 2: Do it "the normal way"
const wrapped2 = (
  <Box>
    <Skeleton />
  </Box>
);

Custom Highlight Background

You may want to make the gradient used in the highlight element narrower or wider. To do this, you can set the customHighlightBackground prop. Here's an example of a narrow highlight:

<Skeleton customHighlightBackground="linear-gradient(90deg, var(--base-color) 40%, var(--highlight-color) 50%, var(--base-color) 60%)" />

If you use this prop, the baseColor and highlightColor props are ignored, but you can still reference their corresponding CSS variables as shown in the above example.

Custom highlight background example

Troubleshooting

The skeleton width is 0 when the parent has display: flex!

In the example below, the width of the skeleton will be 0:

<div style={{ display: 'flex' }}>
  <Skeleton />
</div>

This happens because the skeleton has no intrinsic width. You can fix it by applying flex: 1 to the skeleton container via the containerClassName prop.

For example, if you are using Tailwind, your code would look like this:

<div style={{ display: 'flex' }}>
  <Skeleton containerClassName="flex-1" />
</div>

The height of my container is off by a few pixels!

In the example below, the height of the <div> will be slightly larger than 30 even though the react-loading-skeleton element is exactly 30px.

<div>
  <Skeleton height={30} />
</div>

This is a consequence of how line-height works in CSS. If you need the <div> to be exactly 30px tall, set its line-height to 1. See here for more details.

Contributing

Contributions are welcome! See CONTRIBUTING.md to get started.

Acknowledgements

Our logo is based off an image from Font Awesome. Thanks!

changelog

3.5.0

Features

  • Add optional customHighlightBackground prop. (#233)

3.4.0

Features

  • Remove z-index: 1 from the skeleton. This was a Safari-specific workaround that is no longer necessary in the latest versions of the browser. (#216)

3.3.1

Bug Fixes

  • Fix main and module being incorrect in package.json. (#191)

3.3.0

Features

  • The library is now compatible with TypeScript's "moduleResolution": "nodenext" compiler option. (#187)

3.2.1

Bug Fixes

  • The skeleton now has user-select: none so that it cannot be selected. (#179)

Thanks!

  • @larsmunkholm

3.2.0

Features

  • The skeleton animation no longer plays for users who have enabled the prefers-reduced-motion accessibility setting.

Thanks!

  • @RoseMagura

3.1.1

Chores

  • Add the 'use client' directive to make the library compatible with React Server Components and Next.js 13. (#162)

Thanks!

  • @cravend

3.1.0

Features

  • If count is set to a decimal number like 3.5, the component will display 3 full-width skeletons followed by 1 half-width skeleton. (#136)

3.0.3

Bug Fixes

  • Fix an edge case where the animated highlight had the wrong vertical position (#133)

Thanks!

  • @HexM7

3.0.2

Bug Fixes

  • Fix explicitly setting a Skeleton prop to undefined, like <Skeleton highlightColor={undefined}>, blocking style options from the SkeletonTheme (#128)
    • If you were relying on this behavior to block values from the SkeletonTheme, you can render a nested SkeletonTheme to override a theme defined higher up in the component tree, OR explicitly set one or more Skeleton props back to their default values e.g. <Skeleton baseColor="#ebebeb" />

3.0.1

Bug Fixes

  • Fix circle skeleton animation being broken in Safari (#120)
  • Fix SkeletonProps not being exported from the main entry point (#118)
  • Fix enableAnimation prop having no effect. This was a regression.

3.0.0

Migration Guide

  1. Add the new required CSS import:

    import 'react-loading-skeleton/dist/skeleton.css';
  2. Read the full list of breaking changes to see if any affect you.

Breaking Changes

  • Drop Emotion dependency, add CSS file that must be imported
    • Dropping Emotion avoids conflicts when multiple Emotion versions are used on one page and reduces bundle size
  • Reimplement SkeletonTheme using React context
    • The old SkeletonTheme rendered a <div> which was undesirable in many cases. The new SkeletonTheme does not render any DOM elements.
    • The old SkeletonTheme did not work if the Skeleton was rendered in a portal. The new SkeletonTheme does work in this case.
  • SkeletonTheme: rename the color prop to baseColor
  • Convert to TypeScript
  • Publish code as ES2018 to reduce bundle size
  • Require React >= 16.8.0
  • Drop Internet Explorer support

If you need to support Internet Explorer or use an old version of React, please continue to use react-loading-skeleton v2.

Features

  • Add many new style-related props to SkeletonTheme
  • Publish an ES module in addition to a CommonJS module
  • Add direction prop to support right-to-left animation
  • Add enableAnimation prop to allow disabling the animation
  • Add containerClassName prop to allow customizing the container element
  • Add containerTestId to make testing easier
  • Add aria-live and aria-busy attributes to the skeleton container to improve screen reader support

Other Changes

  • Optimize animation performance:
    • The old animation animated the background-position property which made the browser repaint the gradient on every frame.
    • The new animation animates the transform of a pseudoelement. This avoids repaints and results in an observable decrease in CPU usage.
  • No longer require width and height to be set for the circle prop to work
  • Change the default duration from 1.2 s to 1.5 s
  • Make the default Skeleton base color a tiny bit darker so that the animation is more visible

Bug Fixes

  • Several common issues are now resolved as a result of removing Emotion
  • Fix multi-line skeletons not working with the width prop
  • Fix the type of the wrapper prop in the type definitions

Thanks!

  • @srmagura
  • @aboodz
  • @RoseMagura
  • @saadaouad
  • @rlaunch