Loading

How to use loading states to help users stay informed and engaged while waiting

Overview

The Goal Gradient Effect explains how the tendency to approach a goal increases with proximity to the goal. Loading states reduce the user’s perception of time, and the closer users are to completing a task, the faster they work towards reaching it. By clearly indicating progress, we motivate users to complete tasks.

Sometimes we can't avoid making users wait. Loading states are a visual cue to reassure the user that the system is working.

As a result, loading states help reduce user uncertainty and increase user trust and satisfaction.

 


Loading types

There are two types of loading:

  • Indeterminate loading is used when the duration is uncertain. It’s less informative than determinate loading and is generally used for a waiting time of 1–3 seconds.
  • Determinate loading provides a clear start and end point, giving users a sense of how long they’ll have to wait. It’s generally used for a waiting time of 3+ seconds.

See Response Times for a general guide for which loading patterns to use based on waiting time.

Indeterminate loading

Indeterminate loading is used when the duration is uncertain.

Quick summary

Indeterminate loading type

Purpose

Placement

Spinner

Animated spinning icon for most use-cases

Inline or full-screen

↳ Deployment Spinner

Special type of spinner: animated 8-dot icon to indicate a deployment in progress

Inline

Skeleton Screen

Simplified version of content with a predictable layout, that gives users a sense of what the page will look like

Inline or full-screen

Animated icon or illustration

Special, branded loading state (used sparingly)

Full-screen

Step Indicator

Breaks down a longer wait into smaller chunks by showing how many items have been loaded

Inline or in a Dialog

Spinner

A Spinner is an animated spinning icon. It’s the most versatile loading indicator and works well on a small scale (inline), such as inside a table row or a button.

It’s also appropriate for loading larger-scale content (inline or full-screen) with an unpredictable layout. If the layout is predictable, we recommend using a Skeleton Screen instead.

We use a special 8-dot Deployment Spinner to indicate a deployment in progress. It is displayed:

  • on a specific Release page next to the Project + Release title (e.g. Deploy Azure Web App release 0.0.1 to Development) to indicate the overall release being deployed, and;
  • on the same page as above, in the Task Log tab at the individual step level, to indicate which step(s) are being processed

Spinner

Deployment Spinner

Skeleton Screen

A Skeleton Screen is a simplified version of content that gives users a sense of what the page will look like when it first loads.

It’s used for loading a full page or parts of a page (inline) with a predictable layout. A predictable layout means we know which elements will load, where they will sit on the page, and how they will appear.

It helps to reduce cognitive load and minimizes big jumps in the page layout. The added movement of a pulsing animation also creates the illusion of a shorter wait time.

Animated icon or illustration

An animated icon or illustration is a special, branded loading state.

It’s used only for full-screen loading when the user manually refreshes the page. We use it sparingly to maintain brand impact.

Step Indicator

A Step Indicator breaks down a longer wait into smaller chunks by showing how many items have been loaded. It’s generally displayed at the component-level (inline) or in a Dialog overlay.

If the system is processing multiple items, it gives the user visibility on how many items have been completed. If granular visibility isn’t possible, or the details are irrelevant to the user, a Step Indicator can use general messaging to explain what’s currently happening, such as “Cleaning up duplicates” or “Connecting to server”.

Step Indicator - Dialog

An example of where we currently use a Step Indicator is the Task Log, which displays the individual steps in progress during an active deployment.

Step Indicator

Determinate loading

Determinate loading provides a clear start and end point, giving users a sense of how long they’ll have to wait.

Quick summary

Determinate loading type

Purpose

Placement

Time or Percent Indicator

Display a time or percentage estimate to set user expectations for how long content will take to load

Generally accompany another loading type, such as next to a Progress Bar or inside a determinate Spinner

Progress Bar

Animated horizontal bar indicating a task’s completion status

Inline or full-screen

Interstitial Screen

Transition page for loading longer processes, such as one that results in a significant change, or to block the UI to prevent interruptions or changes to data

Full-screen

”Fake” Loader

An intentional delay to reassure users that a critical action has been processed, or to let users undo an action

Inline, full-screen, or in a Snackbar

Time or Percent Indicator

Time or Percent Indicators display a time or percentage estimate to set user expectations for how long content will take to load. Use when you have a reasonable estimate of the loading time.

These indicators can be used at page-level (full-screen) or component-level (inline) and generally accompany another loading type, such as next to a Progress Bar or inside a determinate Spinner (circle fills up instead of constantly spinning).

Time or Percent Indicator
Don't

Don’t stop progress at 99% if you can’t estimate the length of the task precisely. Use an indeterminate approach instead.

Progress Bar

A Progress Bar is an animated horizontal bar indicating a task’s completion status. The bar visually fills up as the task progresses and reaches the end when the content finishes loading.

It is appropriate for page-level (full-screen) and component-level (inline) loading.

Do

 

Do use a determinate Progress Bar if we can accurately estimate the waiting time.

Caution

The Frontend Foundations Team plans to deprecate the current indeterminate Progress Bar, which continuously fills up and empties, because this lack of feedback isn’t useful for waiting times of 3+ seconds. If the waiting time is 1–3 seconds, use a Spinner or Skeleton Screen instead.

Interstitial Screen

An Interstitial Screen is a full transition page for loading longer processes.

It’s not strictly a determinate loading state because it uses an indeterminate Spinner, but it should also display a Time Indicator with a rough estimate, such as “It should only take a few seconds”.

Use when a loading process results in a significant change, or to block the UI to prevent interruptions or changes to data.

Interstitial Loading Screen

“Fake” Loader

When a critical task or the final step of a tedious workflow is so fast that it’s unnoticeable (less than 0.1 seconds), the user may question whether anything happened and lose trust in the product.

In this situation, consider using a “fake” loader to give the impression that the machine is “working hard”. This is an opportunity to create breathing room to appreciate the effort put into the task and reassure the user that their critical task has completed successfully.

This is also applicable to implementing an undo mechanism. For example, the system may easily delete an entity in an instant, but we can intentionally delay the process by providing the user a brief window to undo the delete action.

Fake Loader - Undo Mechanism

This is considered a determinate loading state because we set the delay based on the scale of the task. For an undo mechanism, for example, we can estimate the typical user reaction time.

 


Response times

Website response times help frame our approach to when we use specific types of loaders.

Quick summary

Response time

Loading approach

Less than 0.1 seconds

No loader (alternatively, see “Fake” Loader)

0.1–1 seconds

No loader

1–3 seconds

Indeterminate loader

3–10 seconds

Determinate loader

10+ seconds

Treat the process as a background task to avoid blocking other interactions

Less than 0.1 seconds

This is instantaneous and isn’t noticeable to the user, so we’d generally display the result immediately.

However, if it’s a critical task or the final step of a tedious workflow, consider using a “fake” loader to give the impression that the machine is “working hard”. This is an opportunity to create breathing room to appreciate the effort put into the task. If it’s so fast that it’s unnoticeable, the user may question whether anything happened and lose trust in the product.

This is considered a determinate loading state because we set the delay based on the scale of the task. For an undo mechanism, for example, we can estimate the typical user reaction time.

0.1–1 seconds

Users can sense a delay, but still feel in control of the overall experience.

Don't show a loading state. Seeing a loading indicator flash on the screen can be distracting and make the product feel slower than it is. It can also be problematic for people with motion sensitivity.

1-3 seconds

As soon as you pass the 1-second mark, the wait becomes noticeable to the user. Use an indeterminate loading state.

3-10 seconds

For 3+ seconds, if possible, use a determinate loading state to keep the user informed about why they're waiting so long.

10+ seconds

A 10+ second delay often leads users to leave a site immediately. Even if they stay, it's harder for them to understand what's going on, making it less likely that they'll succeed in completing complex tasks.

Treat the process as a background task to avoid blocking other interactions if possible. This reduces the interruption caused by a lengthy process and can make wait times feel shorter if users can shift their focus to other tasks.

 


Defining importance

We should consider how much space the loading interaction deserves. The space it takes up reflects its importance.

Full-screen loading

Full-screen loading may give users a sense of security and trust for a critical or high-stakes task. It takes up the entire screen and interrupts the user flow, so use this method cautiously and intentionally.

We use a branded loading state of an animated icon or illustration for full-screen loading. Another option is an Interstitial Screen for loading longer and complex processes.

Full Screen Loading

Inline loading

Inline loading appears at the component level to show that a specific item or action is processing. It is far less obtrusive than full-screen loading and it may let users carry on with their task while items they don’t need are still loading.

The following loading types are recommended for inline loading:

Inline Loading

 


Defining scope

The scope depends on the amount of data being processed and the perceived importance of the task. A few factors inform how we want to return information to a page.

Load items one by one

When displaying more complex and richly formatted components, such as a list of steps in a Process, loading each item one after another can give users something to work with immediately.

Whenever possible, prioritize the most important pieces of data to load first. This could be especially helpful for somebody on a slow network.

Batch loading

For lighter components that exist better as a group, such as a table, it makes more sense to load and show them all at once or at least in batches.

Lazy loading

Lazy loading postpones the loading of additional content in the viewport. It reduces the amount of data needing to be loaded upfront and helps minimize detrimental effects to performance.

We intentionally avoid using Infinite Scroll and “Load More” patterns due to their negative impacts on performance. Furthermore, our customers tend to be searching for specific information and this behaviour is better supported by reliable filters and use of pagination.

Pagination

Pagination is a horizontal set of links to navigate content loaded across multiple pages. It provides users with a sense of place, as they can build a mental map of which object is on which page for future reference.

Pagination

 


Provide feedback

In most circumstances, displaying the content after a page or process finishes loading is sufficient feedback for the user that loading has finished.

However, there are times when the user may require additional feedback, or we must consider whether a loading state is appropriate.

Success or error states

Process completed successfully

If the process finishes successfully, the user can continue with their task. If they’re not navigated to a new context, we should provide some indication of success, such as a green checkmark or a success message.

Success States

Process failed

If the process failed, we should display an error message that explains what went wrong, and if applicable, an action for the user to take. For example, if the user can retry the process, include a button to do so.

Error States

Feedback Indicator

A subtle Feedback Indicator informs users that content is syncing or up to date. It’s used for periodic refetching of data, which is when data is frequently updated on a page, such as during a deployment. This indicator is minimal and unobtrusive.

We shouldn’t use an animated loading state to represent each individual data fetch, because the constant motion will unnecessarily distract the user. It can also be problematic for people with motion sensitivity.

Subtle Feedback Indicator

 


Triggers

It’s important to be aware of the context of the desired loading experience when defining the correct loading pattern.

Passive loading

Passive loading is when the system triggers loading upfront and doesn’t require user input. Examples are loading a data-heavy page, opening a file, or displaying search results.

Active loading

Active loading is when the user triggers loading. Examples are publishing new input data (such as adding a new Project), exporting a large file, or choosing to load more results.

 


Do I need a loading state?

Before deciding which loading state to use, ask yourself whether a loading state is appropriate:

What’s the frequency of updates or changes?

If the data is periodically refetched in the background, a loading state may not be ideal. An animated loader constantly flashing on the screen can be distracting and make the product feel slower than it is. It can also be problematic for people with motion sensitivity.

How much user involvement is there?

If the loading is passive (system-triggered), it should be unobtrusive and quietly happen in the background. Depending on its importance, you may consider using a subtle Feedback Indicator, or nothing at all.

If the loading is active (user-triggered), we should provide a stronger visual cue that the system is responding to their request by using an appropriate determinate or indeterminate loader.

 


Accessibility

Motion

Animated loading indicators help reassure the user that the system isn't frozen, and should not be disabled for users that prefer reduced motion.

However, the animation in loading indicators should be kept as subtle as possible. Large, flashy animations can be harmful to users with sensitivity to motion.

Conveying meaning

Loading indicators are visual and need to be accessible to assistive technologies.

This can be done with a text element we associate using aria-labelledby, or attributes such as alt (on an img element) and title (on an svg element). The loading text element may be visually hidden. You may default to a generic label such as "loading", but try to be specific when possible.

Avoid over-announcing loading states

If you're using multiple loading indicators to convey a cluster of loading content, be mindful about how many announcements will be read aloud to screen reader users. This problem is most likely to happen when using a Skeleton Screen.

Do

Use one announcement for a cluster of loading content.

Don't

Avoid over-announcing loading states.

Feedback

Communicating when a process has started, is in progress, or has completed or failed, can be surfaced to users through a non-displayed role="status" message, such as “finished” or “loading complete”.

Focus management

When focus needs to move after a process finishes loading, it should go to the most logical and predictable location.

  • If it results in navigating to a new page, just rely on the browser's default focus behavior for new pages.
  • If the process fails and a validation message is shown, move focus to the first focusable element in the error message.
  • If the process loads new content, move focus to first focusable element in the newly loaded content.

Resources

 


Other documentation that will help guide your thinking when working with this UI pattern.