Assets path in html.Img broken in multi page app with path variables

I have a multi page app which in the root view has a sidebar. The sidebar has different icons which are placed in the /assets folder. The app structure is similar to this:

DashApp/

  • app.py
  • pages /
    – home.py
    – page1.py
    – page2.py
  • assets/
    –icon.png

In app.py I initialize the layout as:

def layout():
    return html.Div(
        [
            dcc.Location(id="url", refresh=True),
            sidebar,
            html.Div(dash.page_container, className='page-layout', id="page-content")
        ],
        id="main-layout",
        className="body")

And I init dash from flask with this function:

def init_dash(server):
    from flask.helpers import get_root_path
    dash_app = Dash(server=server,
                    routes_pathname_prefix="/dashapp/",
                    use_pages=True,
                    assets_folder="DashApp/assets",
                    pages_folder="DashApp/pages",
                    external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.BOOTSTRAP])
    dash_app.layout = mainLayout()

    return dash_app.server, dash_app

Icons:

html.Img(src="assets/home.svg", className="sidebar-icon"),

When loading home.py, the sidebar correctly loads the icons. On the sidebar, there is a dbc.NavLink which loads page1. Then, inside page1 also the sidebar icons load correctly. So far, so good.

Now, page 2 is accessed with a variable in the path which loads the corresponding information. This page is also accessed through a NavLink. When the page is loaded (NavLinks don’t reload the page by default). Now, while in page 2 if I refresh the page (F5) the images won’t load (broken img icon will show).

page1 and home are defined as:

dash.register_page(__name__, path='/', title='Home')

dash.register_page(__name__, path='/page1', title='Page 1')

page 2 is defined as:

dash.register_page(
    __name__, path_template='/results/page2/<job_name>', name='Page 2 Results')

My Dash app is running inside a flask server with login, so I can see in the console the following:
When loading home and page1, the assets arre accessed correctly with: “GET /dashapp/assets/home.svg HTTP/1.1”
When loading page2, the assets are not found because the assets path changed: “GET /dashapp/results/page2/assets/home.svg HTTP/1.1”

This only happens in pages accessed with path variables (maybe because of the /results/page2 structure?). Do anyone know a workaround or the correct way to handle this? Thanks.

Hello @cdominguez,

Welcome to the community!

So, the thing to keep in mind when adding paths to things like src, just like with paths in python, you are always starting at the same level as whatever you are viewing.

When you are in app, assets gets you into the folder, where as when you are in a folder inside, you need to go ./assets to get you into the proper folder.

For this, you will need to tell the browser that you want to go back a couple of levels, ../assets might get you there, if not, try ././assets.

1 Like

The problem is that the sidebar is always on the top part of the layout and it’s defined only one time. So it should be /assets, and it works most of the time, but when entering pages that are more than 1 level deeper, then the sidebar (that its still defined at the top level, because what changes is the content on dash.page_container) then doesn’t load the icons.

Okay so I fixed it by moving all the assets from the DashApp/assets folder to the static folder that Flask uses when rendering .html pages. Then:

DashApp/ ⭠ Dash app with pages, etc…
static/ ⭠ Static folder containing css and img
main.py ⭠ Flask entry point

html.Img(src="/static/img/home.svg", className="sidebar-icon")

And it will always point to the same folder because it is now an absolute path.

1 Like