3

Dash allows the use of our own CSS style sheets. However, if you are in the scientific field and you are unfamiliar with CSS, you are able to utilize Bootstrap components which makes styling and page-layout extremely easy to piece together.

This is a standard example in dash to create a side bar: """

This app creates a simple sidebar layout using inline style arguments and the
dbc.Nav component.
dcc.Location is used to track the current location. There are two callbacks,
one uses the current location to render the appropriate page content, the other
uses the current location to toggle the "active" properties of the navigation
links.
For more details on building multi-page Dash applications, check out the Dash
documentation: https://dash.plot.ly/urls
"""
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

# the style arguments for the sidebar. We use position:fixed and a fixed width
SIDEBAR_STYLE = {
    "position": "fixed",
    "top": 0,
    "left": 0,
    "bottom": 0,
    "width": "16rem",
    "padding": "2rem 1rem",
    "background-color": "#f8f9fa",
}

# the styles for the main content position it to the right of the sidebar and
# add some padding.
CONTENT_STYLE = {
    "margin-left": "18rem",
    "margin-right": "2rem",
    "padding": "2rem 1rem",
}

sidebar = html.Div(
    [
        html.H2("Sidebar", className="display-4"),
        html.Hr(),
        html.P(
            "A simple sidebar layout with navigation links", className="lead"
        ),
        dbc.Nav(
            [
                dbc.NavLink("Page 1", href="/page-1", id="page-1-link"),
                dbc.NavLink("Page 2", href="/page-2", id="page-2-link"),
                dbc.NavLink("Page 3", href="/page-3", id="page-3-link"),
            ],
            vertical=True,
            pills=True,
        ),
    ],
    style=SIDEBAR_STYLE,
)

content = html.Div(id="page-content", style=CONTENT_STYLE)

app.layout = html.Div([dcc.Location(id="url"), sidebar, content])


# this callback uses the current pathname to set the active state of the
# corresponding nav link to true, allowing users to tell see page they are on
@app.callback(
    [Output(f"page-{i}-link", "active") for i in range(1, 4)],
    [Input("url", "pathname")],
)
def toggle_active_links(pathname):
    if pathname == "/":
        # Treat page 1 as the homepage / index
        return True, False, False
    return [pathname == f"/page-{i}" for i in range(1, 4)]


@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def render_page_content(pathname):
    if pathname in ["/", "/page-1"]:
        return html.P("This is the content of page 1!")
    elif pathname == "/page-2":
        return html.P("This is the content of page 2. Yay!")
    elif pathname == "/page-3":
        return html.P("Oh cool, this is page 3!")
    # If the user tries to reach a different page, return a 404 message
    return dbc.Jumbotron(
        [
            html.H1("404: Not found", className="text-danger"),
            html.Hr(),
            html.P(f"The pathname {pathname} was not recognised..."),
        ]
    )


if __name__ == "__main__":
    app.run_server(port=8888)

Bootstrap nav pills are elements in a nav bar. They are navigation components that allows a user to browse through various options in the layout. example

In a CSS scriptexample, pills have different components that can be style such as:

/* CSS used here will be applied after bootstrap.css */
body {
  background: #000;
}
.nav-pills a {
    color: #ffffff
}

.nav-pills a:hover {
    color: #560000;
    border-radius: 0px;
}

.nav-pills .active a:hover {
    color: #560000;
    border-radius: 0px;
}
.nav>li>a:hover, 
.nav>li>a:focus {
    color: #560000;
    border-radius: 0px;
}

I would like to update the pill styles through my python script and change the colour of pills when hovered over, when active and I would like to change the font type and it's text colour . I am still familiarizing myself with CSS, hence I would rather update it through the python script. I did override CSS styles successfully, by setting the style parameter.

According the Dash Bootstrap components I can style pills to nav items as stated below:

pills (boolean, optional): Apply pill styling to nav items. Active items will be indicated by a pill.

I have edited the code as such:

sidebar = html.Div(
    [
        html.H2("Sidebar", className="display-4"),
        html.Hr(),
        html.P(
            "A simple sidebar layout with navigation links", className="lead"
        ),
        dbc.Nav(
            [
                dbc.NavItem(dbc.NavLink("Page 1", href="/page-1", id="page-1-link"), style={"background-color": "grey"}),
                dbc.NavLink("Page 2", href="/page-2", id="page-2-link"),
                dbc.NavLink("Page 3", href="/page-3", id="page-3-link"),
            ],
            vertical=True,
            pills=True,

           # className="nav navbar-nav",#"nav nav-pills hidden-sm",
            #style ={"li:hover" =""}

        ),
    ],
    style=SIDEBAR_STYLE,
)

SideBar

This would only change the background colour not the pill colour and font colour when hovered on or active. What is the syntax in python? I have tried many options in the code and I have searched for the styling syntax in python but I have still not come across the equivalent python styling syntax example.

The closest I have come to changing the pill styles is by changing the available bootstrap style sheets:

app = dash.Dash(external_stylesheets=[dbc.themes.FLATLY])

Flatly bootstrap theme

You can view the various themes and its code in html here

Sade
  • 450
  • 7
  • 27

2 Answers2

3

I strongly recommend you to take the approach of handling pseudo class styles like :hover and :active in your css stylesheets.

For including css stylesheets see the documentation here. Basically you only need an assets folder in your root directory and put .css files inside.

So you could add a className property to each NavLink, target the elements using the class in your stylesheet and add :hover and :active styles as you want.

Inside your Dash layout:

dbc.NavLink("Page 1", href="/page-1", id="page-1-link", className="page-link"),

Inside a css file in your assets directory:

.page-link:hover {
  background-color: green;
}

.page-link:active {
  background-color: blue;
}

You could also include scripts in the assets folder and style the elements using Javascript if you need to have it be dynamic in a way which is not possible with css.

For why your approach doesn't work in the way you expect with inline styles see CSS Pseudo-classes with inline styles.

Now it is possible to use Location to listen for route changes and change the active state of each NavLink according to the current route. Again I recommend the much simpler and also more easily extensible css approach and the following approach also doesn't work on hover, but you could do something like this to change styles on click:

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

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

links = [
    {"id": "page-1-link", "href": "/page-1", "link-text": "Page 1"},
    {"id": "page-2-link", "href": "/page-2", "link-text": "Page 2"},
    {"id": "page-3-link", "href": "/page-3", "link-text": "Page 3"},
]

sidebar = html.Div(
    [
        dcc.Location(id="url", refresh=False),
        html.H2("Sidebar", className="display-4"),
        html.Hr(),
        html.P("A simple sidebar layout with navigation links", className="lead"),
        dbc.Nav(
            [
                dbc.NavItem(
                    dbc.NavLink(link["link-text"], href=link["href"], id=link["id"])
                )
                for link in links
            ],
            vertical=True,
            pills=True,
        ),
    ],
)

app.layout = sidebar


@app.callback(
    [Output(link["id"], "active") for link in links],
    Input("url", "pathname"),
    prevent_initial_call=True,
)
def display_page(pathname):
    actives_list = [False for link in links]

    if pathname == "/":
        return actives_list

    actives_list[int(pathname[-1]) - 1] = True

    return actives_list


if __name__ == "__main__":
    app.run_server(port=8888)
5eb
  • 14,798
  • 5
  • 21
  • 65
0

With this Nav:

dbc.NavLink("Page 1", href="/page-1", id="page-1-link")

Just add the following to your .css file in your assets folder, and it will do the trick.

.nav-pills .nav-link.active {
    color: #fff;
    background-color: orange;
}
QQQ
  • 21
  • 1