Show a full-screen loading spinner on app start-up, then remove it

Hi,

I wanted to share an effective solution to showing a spinner (or similar loading animation) while the app is starting up, and then removing it.
This is relevant for an app with lots of callbacks causing noticeable start-up time, where no single component or callback is the culprit.

TL;DR:

  1. Add a new div to the app, alongside the main layout div, which has the loading spinner component as its only child.
  2. Use a callback that takes as Input the main layout div’s loading state, and outputs None to the loading spinner div’s children.
    Also read the State of the loading spinner div’s children to raise PreventUpdate if the spinner has already been removed.

example

This example uses the very cool new dash-loading-spinners library:

layout:

from dash import html
import dash_loading_spinners

app.layout = html.Div(
     children=[
             html.Div(
                 id="div-loading",
                 children=[
                     dash_loading_spinners.Pacman(
                         fullscreen=True, 
                         id="loading-whole-app"
                     )
                 ]
             ),
             html.Div(
                 className="div-app",
                 id="div-app",
                 children = [ #  app layout here
                ]
             )
         ]
     )

callback:

  @app.callback(
        Output("div-loading", "children"),
        [
            Input("div-app", "loading_state")
        ],
        [
            State("div-loading", "children"),
        ]
    )
    def hide_loading_after_startup(
        loading_state, 
        children
        ):
        if children:
            print("remove loading spinner!")
            return None
        print("spinner already gone!")
        raise PreventUpdate

More detail:

There are some excellent component (libraries) out there for showing a spinner:

And two main ways to use them:

  1. Set up a spinner without children components, and use a callback to change its behavior or remove it
  2. Pass components to the spinner as children and the spinner will show while the child’s loading state shows it is loading.

The problems I encountered were mainly:

  • How to monitor the whole app
  • How to get a smooth loading spinner animation that doesn’t flicker as loading state switches back and forth during startup?
  • How to get rid of the spinner after initial load (or calibrate it so it doesn’t fire every time a callback runs)

When using approach 2 of passing children components, dcc.Loading was the only component to show a smooth continuous animation, but doesn’t offer any obvious ways to calibrate or remove the spinner. The other libraries show a flickering spinner on startup, and have more (but limited) options for calibrating the spinner after start up (e.g. adding a delay to avoid triggering spinner on every callback).

Depending on the app’s CSS, it may be necessary to add some styling to make sure that the spinner and its backdrop (if desired) cover other components, e.g. through the z-index CSS property.

The solution here worked well for me, hope others can use it.

10 Likes

This is amazing, definitely adding this to my next project.

Thanks for sharing @jjt3f2188
I’ve received multiple inquiries asking how to do this over the past year. Now, it seems the community has a solution thanks to you. :orange_heart:

Wow that is super cool! Thanks @jjt3f2188 ! I wonder if there is a way to incorporate this in with the loading states css. I used the code below to show a generic ‘Loading, please be patient…’ Would be super cool to be add in the spinners in the css. I haven’t done enough research, but do you know if there is a way to incorporate the spinners into css code?

I’ve added in your code into one of my multi-page apps which is super cool, but the pacman spinner is only there for a short while as the bulk of the loading time is spent in ‘Loading, please be patient.’ I’ve also commented out the ‘raise PreventUpdate’ because this is in a multi-page app. So whenever a user clicks on that page I want the pacman to show up.

*[data-dash-is-loading="true"]{
    visibility: hidden;
}
*[data-dash-is-loading="true"]::before{
    content: "Loading, please be patient..";
    display: inline-block;
    color: magenta;
    visibility: visible;
}
1 Like

@johnkangw haven’t tried targeting the loading states with CSS.
Do let us know if you discover any nice tricks!
By the way, the approach I outlined in the OP was meant to be compatible with using additional spinners to wrap individual components to generate loading animations while app is up and running.

Check out this thread Change "Loading..." to a spinner for a related example. I think it could be adapted to your use case?

Nice! Thanks! Your code worked and allowed me to show a spinner when loading the Dash initially. I wasn’t able to get it to work to show a spinner when loading separate pages/components though.

I’oL be adding this to my last project. Thank you!

1 Like