Static elements: For elements of the page that won’t require loading, such as headings, body copy, buttons, and borders, include this as static elements of the design. In other words, only skeleton load data values/content, not containers. This avoids the need to build custom loading elements for a variety of containers and minimizes jank when data/content arrives.
Shape: Loading placeholders follow the shape and form of what will be loaded – the width, height, colors and text line-heights align to the built components.
Position: Loading placeholders sit in the same position on the screen as the live elements, to avoid the feeling of things jumping around on the page.
Be subtle, because it’s not a real, interactive interface.
Be flexible to an unknown number of items or shape of data being loaded. This might be indicated either through composition to suggest the shape of what will arrive, or through repeatable elements. Show the minimum number of items as a skeleton before loading however many content items in.
If the skeleton loading will load in content when it’s ready without refreshing the page, animate the loading placeholders. We don’t currently use gradients in our branding aesthetic, so for ‘shimmering’ skeletons we opt for opacity changes rather than animated gradients.
If data sometimes arrives in less than 300ms, still show a loading skeleton for at least 300ms to avoid distracting people with an unnecessary skeleton. That is, don’t show a skeleton for 100ms before content appears as that will feel slower and be a distracting, jarring change.
When to use and when not to use
When to use
Use a loading skeleton when a loading spinner is not prominent enough.
Use when there’s more than 1 element loading at the same time that requires an indicator.
Use on high-traffic pages, such as our account dashboard.
Use when data takes more than 300ms to load on an average connection for our user base.
When not to use
For a long-running process or background process, e.g. importing data or exporting reports, use a progress bar (link to come) instead.
For fast processes that take less than 300ms, consider a spinner or no loading state at all.
For a tiny, inline action or feedback, e.g. clicked a button and the action will take time, use a loading spinner (link to come) instead.
For low-traffic pages, such as super-user only admin pages, use a loading spinner instead.
If a page refresh is required, use an Empty State with a Call To Action to refresh.
For introducing content with flair, use a choreographed or stylized entrance. In contrast to a placeholder loading skeleton, choreographed or stylized entrances don’t care how long content takes to load. For example, the whole page might be loaded already, but we only reveal each section with a fade as the person scrolls down the page. A single stylized entrance may mask and replace a loading spinner.