Plotly Challenge - Build and Publish Dash Hooks

Challenge:

With the goal of enhancing the Dash toolkit and making Dash apps even more versatile, we challenge the Plotly community to build installable plugins.

The winning plugins will be judged according to the following categories:

  • Creativity of the plugin
  • Ease of use of the plugin
  • How helpful the plugin is to the Dash ecosystem

The winners will be announced at the end of June and will receive the following rewards:

:1st_place_medal: $250 USD

:2nd_place_medal: $125 USD

:3rd_place_medal: $50 USD

To participate in the challenge, please share your plugins by replying to this Forum topic by midnight Monday (your time zone), June 30. Please include a link to the plugins on PyPI, the GitHub repo, and a short description.

What are Dash Plugins & Hooks:

Starting from Dash version 3.0.3 Dash provides a system of hooks for creating installable plugins that can extend the functionality of Dash apps and that can be used across multiple apps. You can use hooks to add to an app’s layout, add callbacks, routes, or error handlers.

One big advantage of Dash hooks is that you can share your custom-made plugin with the rest of the Plotly Dash community by publishing it to PyPI. Here’s an example of my colleague, @nathandrezner 's, Dash Stylish Header plugin on PyPI and GitHub, which adds a header to your app with a customizable title.

To use it, simply pip install dash-stylish-header.
Then, in your own app.py file, add the following:

from dash import Dash, html
from dash_stylish_header import register_hooks

# Explicitly register hooks
register_hooks(title="My Dash App")
app = Dash()

Here’s another sample Dash Hook created by community member, Robert, that reads the current logged in user (not yet published on PyPI ).

Resources:

3 Likes

Super excited about this challenge and to see how creative folks will get with Hooks. We’ve already seen some fabulous examples of Dash Hooks and I’m looking forward to being surprised by new ideas ITT over the next few weeks. Thanks @adamschroeder for organizing!

1 Like

The github link doesn’t work: https://github.com/plotly/dash-stylish-header

1 Like

My bad, @ribab . The repo was private. It is now public.
Thank you for flagging.

I think the hooks framework looks really interesting! Before I dive in, I have a few (structural) questions though that I would like to have cleared out,

  • Is there a preferred naming convention for dash hooks? I guess it would be a lot easier to find hooks, if the packages were named consistently, e.g. prefixed with dash, or dash-hooks, or …
  • What is the best practice for publishing a collection of hooks? Should it be one package per hook (that can quickly become a lot of packages, assuming each hook is kept simple)? Or one package with multiple hooks? In the latter case, what is the preferred way to configure which hooks to enable?

Maybe @adamschroeder or @nathandrezner can help? :slight_smile:

3 Likes

Good questions!

We see Dash components usually named as dash-*-components, so something like dash-*-hooks seems reasonable. That being said, the fact that something is implemented with hooks might be an implementation detail, so just dash-* could be sufficient (like my dash-stylish-header example).

If you’re publishing a collection of hooks, we don’t really have a recommended pattern, it’s up to you. Hooks are more traditional modules as compared to component packages, so you can get creative with how you structure your imports and syntax. This is a pretty good tutorial on strategies for structuring modules: Structuring Your Project — The Hitchhiker's Guide to Python

1 Like

Thanks everyone for joining the live demo earlier today.

Here’s the recording in case you missed it and want to watch it later.

1 Like

Hi everyone, and thank you very much for sharing this challenge. I’d like to share my Dash plugin using hooks called dash-customizable-app-style.

Description: The plugin adds a top button to the Dash app to show/hide three selectors that allows to change the background color, the text color and the font family of the entire app.

Github: Dash Customizable App Style on Github

Pypi: Dash Customizable App Style on Pypi

6 Likes

Welcome to the community, @Xavi.LL :waving_hand: . Where have you been hiding all this time?

Awesome Dash Hooks. I just installed it and tried it out on the Figure Friday week 23 sample app.

I see that the styling activated on the html.H1() component, but not the Grid and the graphs. Can I get the styling to activate on those components as well?

from dash import Dash, dcc, html
import dash_ag_grid as dag
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc
import dash_customizable_app_style as style_plugin


df = pd.read_csv("https://raw.githubusercontent.com/plotly/Figure-Friday/refs/heads/main/2025/week-23/steak-risk-survey.csv")

# remove rows with empty values from Gender column
df = df[df['Gender'].notna()]

fig = px.bar(df, x='How do you like your steak prepared?', facet_row='Gender')

grid = dag.AgGrid(
    rowData=df.to_dict("records"),
    columnDefs=[{"field": i, 'filter': True, 'sortable': True} for i in df.columns],
    dashGridOptions={"pagination": True},
    columnSize="sizeToFit"
)

app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(id="main_container", children=[
    style_plugin.customize_app_selectors(),
    html.H1("Dash App with Background Color Plugin"),
    grid,
    dcc.Graph(figure=fig)
])


if __name__ == "__main__":
    app.run(debug=False)

2 Likes

Hi @adamschroeder ! Nice to talk again with you. I’ve been a little busy.

Good point what you’re asking, I haven’t thought about the AgGrid and Graph’s style, and I was focused only in the main container of the layout.

I have updated the Github repository, and uploaded on Pypi a new version (0.0.6) of the plugin that also manages the AgGrid and Graph’s styling.

Thank you very much for the answering and for the report. Makes the plugin much more useful.

from dash import html, Dash, dcc
import dash_bootstrap_components as dbc
import dash_customizable_app_style as style_plugin
import dash_ag_grid as dag
import plotly.express as px
import pandas as pd

# Importing dataset for the example
df                  = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')

grid = dag.AgGrid(
    # To be able to also update AgGrid's background color, text color
    # and font family, set a pattern-matching ID for them as following.
    id={"type": "grid", "index": "grid_name"},
    rowData=df.to_dict("records"),
    columnDefs=[{"field": i, 'filter': True, 'sortable': True} for i in df.columns],
    dashGridOptions={"pagination": True},
    columnSize="sizeToFit"
)

# Creating sample figures
line_figure         = px.line(df, x='year', y='pop')
histofram_figure    = px.histogram(df, x='year', y='pop')

# Initialize the app
app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

# App layout
app.layout = html.Div(
    id       = "main_container",
    style    = {"minHeight": "100vh"},
    children = [

        # Rregister hooks
        style_plugin.customize_app_selectors(),

        # Informative text
        html.H1("Dash App with Background Color Plugin"),
        html.P("Use the color picker above to change the background color."),

        grid,

        # To be able to also update Figure's background color, text color
        # and font family, set a pattern-matching ID for them as following.
        dcc.Graph(id={"type": "graph", "index": "line"}, figure=line_figure),
        dcc.Graph(id={"type": "graph", "index": "histogram"}, figure=histofram_figure)
    ]
)

# To update Figures from an @app.callback

# @app.callback(
#    Output({"type": "graph", "index": "line"}, "figure"),
#    Rest of your callback....


if __name__ == "__main__":
    app.run(debug=True)
2 Likes

In terms of naming, for projects of the hooks type, wouldn’t it be more appropriate to add the “hook” or “plugin” suffix to the name, just as many component libraries end with “components”.:thinking:

Pretty cool :sunglasses:
Thanks for the update.

1 Like

Hello everyone, for this challenge activity, the Dash plugin based on hooks that I want to share is dash-offline-detect-plugin

Description: This plugin can quickly and easily add an application service liveness detection function to Dash applications (especially in the case of production environment deployment). Once the backend service of a Dash application that the user has opened cannot be connected, the Dash application with this plugin enabled will immediately display relevant prompt information on the front-end page. When the service is restored, the prompt information will be automatically removed.

demo

Github: dash-offline-detect-plugin on Github

Pypi: dash-offline-detect-plugin on Pypi

Demo app:

import dash
from dash import html

# Import the offline detect plugin
from dash_offline_detect_plugin import setup_offline_detect_plugin

# Enable the offline detect plugin for the current app, default interval is 5000ms
setup_offline_detect_plugin()

app = dash.Dash(__name__)

app.layout = html.Div("Test App.", style={"padding": 50})

if __name__ == "__main__":
    app.run()

7 Likes

After continuing to study the writing method of Dash hooks in the documentation, I realized that through this hooks mechanism, many practical functions in the JavaScript ecosystem can be integrated into our Dash applications quickly and effectively. The second Dash plugin based on Dash hooks that I want to share is dash-disable-devtool-plugin.

Description: This plugin can quickly add security protection to Dash applications, blocking most attempts to debug the application through the browser developer tools. After enabling dash-disable-devtool-plugin in a Dash application with a single line code, once someone tries to open the developer tools to debug our Dash application in the browser, the detection will be triggered, automatically clearing the page content and replacing it with the corresponding warning message.

In addition, through dash-disable-devtool-plugin, a series of shortcut parameters can be used to selectively disable operations such as the right-click menu, text selection, copy, and paste within the page to meet different page protection requirements.

demo

Github: dash-disable-devtool-plugin on Github

Pypi: dash-disable-devtool-plugin on Pypi

Demo app:

import dash
from dash import html

# Import the disable devtool plugin
from dash_disable_devtool_plugin import setup_disable_devtool_plugin

# Enable the disable devtool plugin for the current app
setup_disable_devtool_plugin()

app = dash.Dash(__name__)

app.layout = html.Div("Test App.", style={"padding": 50})

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

2 Likes

Hey @Xavi.LL I had a similar idea too. Btw looks pretty neat. :smiley:

1 Like

@CNFeffery those are some super cool use cases for Hooks, love it.

3 Likes

Hi all, I finished my first hook.

Name of the hook: dash-stylish-header-footer-hook

This hook provides two hooks for Dash applications: a stylish, customizable header and a footer. The add_header injects a modern, gradient-styled header with external fonts and normalization CSS, while add_footer_hook appends a styled footer to the layout, ensuring no duplicates. Both header and footer styles can be easily customized via function parameters. These hooks automate the addition of these elements, making it simple to create a consistent, professional look for any Dash app.

Installation and usage:

pip install dash-stylish-header-footer-hook
from dash import Dash
import dash_stylish_header_footer_hook  

# Register the header with custom title
dash_stylish_header_footer_hook.add_header(
    title="My Dash App",
    gradient="linear-gradient(90deg, black, red)"
)
dash_stylish_header_footer_hook.add_footer_hook(
    text="©2025 My Dash App",
    background="black",
    color="magenta",
    padding="20px 40px"
)

app = Dash(__name__)
# Rest of your app code...

Links:
PyPi
GitHub

This is my first hook, I tried something simple but useful thing.:slight_smile:

3 Likes