Execute javascript for sidebar

Hi All,

I want to add a nice sidebar to my application. For that, i need some javascript. However, i dont know how to execute the javascript in my plotly app. I tried to save the script in ‘custom-script.js’ but it does not work. I also googled about html.Script, but the documentation of plotly tells me that element is not working.

I heard i can use clientside callbacks, but i dont know how to do that. How could i let my app execute the following javascript:

Thanks!

const body = document.querySelector(“body”),
sidebar = body.querySelector(“nav”),
toggle = body.querySelector(“.toggle”),
searchBtn = body.querySelector(“.search-box”),
modeSwitch = body.querySelector(“.toggle-switch”),
modeText = body.querySelector(“.mode-text”);

toggle.addEventListener(“click”, () => {
sidebar.classList.toggle(“close”);
});

searchBtn.addEventListener(“click”, () => {
sidebar.classList.remove(“close”);
});

modeSwitch.addEventListener(“click”, () => {
body.classList.toggle(“dark”);
if (body.classList.contains(“dark”)) {
modeText.innerText = “Light mode”;
} else {
modeText.innerText = “Dark mode”;
}
});

Hello @nickhes,

For JavaScript to work on elements in the layout, the elements have to exist first.

When you load a page, the elements actually haven’t rendered yet, so you have to delay when the elements get listeners added.

You can do this by wrapping this whole statement in a function, then call this function with document.addEventListener(“ready”, function() {customfunction()})

It might be easier to have a clientside callback, because this would trigger as soon as the layout gets rendered.

All you have to do is take your JavaScript that you have and place it inside of a Js function written inside of the callback function spot.

Or, you could just call the custom function from the clientside callback, that choice is up to you. Just remember to return something to make it a valid callback.

2 Likes

thanks a lot. Could you maybe add a simple example on how to implement this? Thanks!!

Sure thing, here is the app.py to go with it:

from dash import Dash, html
import pandas as pd

app = Dash(__name__)

app.layout = html.Div(
    [
        html.Div(id='nav', children=[html.Button('ToggleNavBar', id='toggleNav', className='toggle'),

        html.Div([html.Div('Light Mode', className='mode-text'),
        html.Button('Toggle DarkMode',className="toggle-switch")])]),
        html.Div([html.Button('Open Search', className="search-box"),
                  ], id='page-content')
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True)

js file

function addListeners() {
    console.log('adding listeners')
    const body = document.querySelector("body"),
    sidebar = body.querySelector("#nav"),
    toggle = body.querySelector(".toggle"),
    searchBtn = body.querySelector(".search-box"),
    modeSwitch = body.querySelector(".toggle-switch"),
    modeText = body.querySelector(".mode-text");

    toggle.addEventListener("click", function() {
        sidebar.classList.toggle("close");
        document.getElementById("page-content").classList.toggle("close");
    });

    searchBtn.addEventListener("click", function() {
        sidebar.classList.remove("close");
        document.getElementById("page-content").classList.remove("close");
    });

    modeSwitch.addEventListener("click", function() {
        body.classList.toggle("dark");
        if (body.classList.contains("dark")) {
            modeText.innerText = "Dark mode";
        } else {
            modeText.innerText = "Light mode";
        }
    });
}

document.addEventListener("DOMContentLoaded", function() {
    setTimeout(function() {addListeners()}, 1000)
})

css file for show:


body.dark {
    background: gray;
}

body.dark button {
    background-color: silver;
}

#nav {
    width: 300px;
    border-radius: 20px;
    border: 1pt solid black;
    height: 100vh;
    position: absolute;
    left:-30px;
    top: 0px;
    padding-left: 30px;
    background-color: gray;
    z-index: 2;
    box-shadow: 5px 0px 15px black;
    transition: 0.5s all;
}

#nav.close {
    width: 100px;
}

#page-content {
    position: absolute;
    left: 300px;
    background: #F5F5F5;
    padding-left: 40px;
    padding-top: 5px;
    top: 0px;
    height: 100vh;
    width: 100%;
    min-width: calc(100vw-300px);
    transition: 0.5s all;
}

#page-content.close {
    left: 100px;
}

.dark #page-content {
    background-color: gray;
}

.dark #nav {
    background-color: #333;
}

.dark button {
    color: silver;
}

If you were to do a client_side callback, remove the spot where you add the listeners based upon document ready:

app.clientside_callback(
    """function () {
        addListeners()
        return 0
    }""",
    Output('nav','n_clicks'),
    Input('nav','children')
)
2 Likes