Building Dashboard using Dash — Responsive Navbar Part — 3, client-side callback
Introduction
If you followed the previous parts of this tutorial and interacted with the navbar through the provided link, you may have noticed that the navbar has some lag after clicking the buttons. Unfortunately, this lag can negatively impact the user experience, leading to frustration, decreased engagement, and ultimately resulting in the user abandoning the application.
Thankfully, Dash provides a solution to this problem with client-side callbacks. In this section, we will explore the use of client-side callbacks and see how we can implement them to improve the performance of our sidebar component.
Problem
When a button is clicked, it triggers communication with the dash-renderer. The dash-renderer then identifies the appropriate callbacks that must be executed in response to the user input.
The process of executing a callback typically involves three steps: sending a request to the server, waiting for the server to respond, and downloading the updated content. This entire process can take around 300+ ms, with most of the time spent waiting for the server's response.
Solution
One solution to address the lag and improve the performance of Dash applications is to use client-side callbacks. By implementing client-side callbacks, we can minimize the time spent waiting for the server response and provide a more responsive and seamless user experience.
Client-side callbacks allow us to execute callbacks directly on the client-side, without needing to make a round trip to the server. This means that only the necessary data is sent to the server, resulting in a faster response time and reduced server load.
To use client-side callbacks in Dash, we need to define Output
and Input
as we do, but additionally have to define a JavaScript function as the first argument to the @app.callback
decorator.
Let’s Code
We can start by focusing on the callback corresponding to the button click that renders the size of the navbar. This callback is a good candidate for client-side optimization, as it involves updating a single value in response to user input.
@dash.callback(
Output("sidebar", "width"), #what we wanted to change
Input("sidebar-button", "n_clicks"), #width will change when btn is triggered
State('sidebar','width') #store inital width
)
def sidebar(opened, width):
if opened:
if width['base'] == 300: #if initial width is 300 then return 70
return {"base": 70}
else:
return {'base':300}
# will update it to
app.clientside_callback(
ClientsideFunction(namespace='clientside',
function_name='handle_click_sidebar_width'),
Output("sidebar", "width"),
[Input("sidebar-button", "n_clicks")],
[State('sidebar','width')]
)
Well, three arguments are the same and one client-side function. ClientsideFunction(namespace='clientside',function_name='handle_click_sidebar_width')
: This argument specifies the client-side function that should be triggered when the callback is called. The namespace
parameter specifies the namespace of the JavaScript function (in this case, "clientside"), and the function_name
parameter specifies the name of the function ("handle_click_sidebar_width").
Create a new file script.js
in assets/
folder. It will contain all Javascript we will be using.
const handle_click_sidebar_width = (n_clicks, width) => {
const current_width = parseInt(width.base)
if (n_clicks > 0 & current_width == 300) {
return {base:70};
} else {
return {base:300};
}
}
We have created a JavaScript function called handle_click_sidebar_width
. It takes two parameters: n_clicks
and width
.
The function first extracts the current width of the sidebar component from the width
parameter, which is a dictionary with key base
, using parseInt()
and stores it in current_width
.
Next, it checks if the number of clicks (n_clicks
) is greater than zero and the current width is equal to 300. If both conditions are true, it returns an object with a new width value of 70 for the base
property. This reduces the width of the sidebar from 300 to 70 when the sidebar button is clicked.
If the conditions are not met, means the current width of the navbar is 70, so the function returns an object with a new width value of 300 for the base
property. This restores the original width of the sidebar when the button is clicked again.
In a similar manner, the callback for the second button, which renders the drawer, can also benefit from client-side optimization. This is because the callback returns a Boolean value in response to user input, and thus can be executed more efficiently on the client side.
@dash.callback(
Output("drawer-simple", "opened"),
Input("drawer-demo-button", "n_clicks"),
prevent_initial_call=True,
)
def drawer_dem(n_clicks):
return True
# will update it to
dash.clientside_callback(
ClientsideFunction(namespace='clientside', function_name='handle_click'),
Output("drawer-simple2", "opened"),
[Input("drawer-demo-button2", "n_clicks")]
)
And in javascript, we will add the function handle_click
and an object in JavaScript that provides a way to define client-side functions that can be called from a Dash application. The clientside
property of this object is used to store an object containing the client-side functions. In our case, the object has two properties: handle_click
and handle_click_sidebar_width
, which correspond to the two client-side functions used in the Dash application.
const handle_click = (n_clicks) => {
if (n_clicks > 0) {
return true;
} else {
return '';
}
};
window.dash_clientside = { clientside: { handle_click,handle_click_sidebar_width }};
The result is phenomenal, can check it out here.
Conclusion
In conclusion, using client-side callbacks can significantly improve the performance and user experience of a Dash application. By optimizing certain callbacks to be executed on the client side, the application can reduce the time spent waiting for server responses and provide faster, more responsive interactions. The ClientsideFunction
component and window.dash_clientside
the object provides powerful tools for defining and managing client-side functions within a Dash application. Therefore, it is highly recommended to explore and utilize these tools in order to create highly performant and user-friendly Dash applications.
One can view the code by visiting the GitHub link. I hope you’ve found this guide informative and helpful in creating a visually appealing dashboard with Dash.
Please feel free to leave a comment below. Any suggestions or questions will help us improve future content and better serve your needs. Thank you for reading and a clap will not hurt, isn’t it?