Black Lives Matter. Please consider donating to Black Girls Code today.
Learn how to use COVID-19 data in open source Dash apps. Register for the Sept 23rd webinar with IQT!

Lose CSS after structuring Multi-Page Apps and URL Support

No matter which method I tried, the app1 and app2 lost CSS styles.

This works for me in the dash-docs repo (https://github.com/plotly/dash-docs)

Can you create a small, reproducable example that demonstrates your issue?

File structure:
- app.py
- index.py
- apps
   |-- __init__.py
   |-- app1.py
   |-- app2.py

app.py

import dash

app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True

app.css.config.serve_locally = True

external_css = ["static/base.css",
                "static/custom.css"]
for css in external_css:
    app.css.append_css({"external_url": css})

index.py

from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

from app import app
from apps import app1, app2



app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])


@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/':
         return app1.layout
    elif pathname == '/apps/app2':
         return app2.layout
    else:
        return '404'
        
if __name__ == '__main__':
    app.run_server(debug=True)

app1

from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc

from app import app

layout = html.Div([
    html.H3('App 1'),
    dcc.Dropdown(
        id='app-1-dropdown',
        options=[
            {'label': 'App 1 - {}'.format(i), 'value': i} for i in [
                'NYC', 'MTL', 'LA'
            ]
        ]
    ),
    html.Div(id='app-1-display-value'),
    dcc.Link('Go to App 2', href='/apps/app2')
],className='container')


@app.callback(
    Output('app-1-display-value', 'children'),
    [Input('app-1-dropdown', 'value')])
def display_value(value):
    return 'You have selected "{}"'.format(value)

app2

from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc

from app import app

layout = html.Div([
    html.H3('App 2'),
    dcc.Dropdown(
        id='app-1-dropdown',
        options=[
            {'label': 'App 2 - {}'.format(i), 'value': i} for i in [
                'NYC', 'MTL', 'LA'
            ]
        ]
    ),
    html.Div(id='app-2-display-value'),
    dcc.Link('Go to App 2', href='/')
],className='example-container')


@app.callback(
    Output('app-2-display-value', 'children'),
    [Input('app-2-dropdown', 'value')])
def display_value(value):
    return 'You have selected "{}"'.format(value)

I try to pass CSS thru className inside the app1 and app2, but it didnt work. The CSS files are from DASH Documents.

@BingWong - In addition to doing append_css, you’ll need to add a static file serving URL route with flask. Modify app.py to look something like:

import dash
import os

from flask import send_from_directory


app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True

external_css = [
    'https://codepen.io/chriddyp/pen/bWLwgP.css',
    '/static/base.css',
    '/static/custom.css'
]
for css in external_css:
    app.css.append_css({"external_url": css})


@app.server.route('/static/<path:path>')
def static_file(path):
    static_folder = os.path.join(os.getcwd(), 'static')
    return send_from_directory(static_folder, path)
1 Like

It works like a charm!! thanks

1 Like

I tested it on heroku last night. For those who want to deploy it to heroku, you need to modify Procfile fileand index.py in order to make it work.

Procfile:

web: gunicorn index:server

index.py

from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

from app import app
from apps import app1, app2

#here is the line we need to add.
server = app.server


app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])


@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/':
         return app1.layout
    elif pathname == '/apps/app2':
         return app2.layout
    else:
        return '404'
        
if __name__ == '__main__':
    app.run_server(debug=True)
1 Like