pythonplotly-dash

How to show a hover message on a disabled toggle button in Dash?


I'm working on a Dash application where I have a toggle button (dbc.Switch) that gets disabled based on the user's input. I would like to display a hover tooltip message when the toggle button is disabled. However, I noticed that the tooltip doesn't appear when the button is disabled. Here's the code I'm using:

import dash_bootstrap_components as dbc
from dash import Dash, html, dcc, Input, Output

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

app.layout = html.Div(
    [
        dcc.Input(id='number-input', type='number', placeholder='Enter a number'),
        dbc.Switch(
            id="toggle-button",
            label="Toggle Button",
            style={"display": "inline-block", "margin-right": "10px"}
        ),
        dbc.Tooltip(
            id="toggle-tooltip",
            target="toggle-button",
            placement="top"
        ),
    ]
)

@app.callback(
    Output("toggle-button", "disabled"),
    Output("toggle-tooltip", "children"),
    Input("number-input", "value")
)
def update_toggle(number):
    if number is not None and number % 2 == 0:
        return False, "Disabled for even numbers"
    else:
        return True, "This is a toggle button"

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

The toggle-button gets disabled when the input number is even, and I would like the toggle-tooltip to display a message explaining why it's disabled this should be come when i hover on toggle. The tooltip should still be visible when hovering over the disabled button.


Solution

  • The tooltip won't show up if its target is disabled.

    One way to fix this is to wrap the "toggle-button" switch into a component and use that component as the tooltip target, eg.

    app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
    
    app.layout = html.Div([
        dcc.Input(id='number-input', type='number', placeholder='Enter a number'),
        html.Span(id='toggle-button-wrapper', children=[
            dbc.Switch(
                id="toggle-button",
                label="Toggle Button",
                style={"display": "inline-block", "margin-right": "10px"}
            )
        ]),
        dbc.Tooltip(
            id="toggle-tooltip",
            target="toggle-button-wrapper",
            placement="top"
        )
    ])
    
    @app.callback(
        Output("toggle-button", "disabled"),
        Output("toggle-tooltip", "children"),
        Input("number-input", "value")
    )
    def update_toggle(number):
        if number is not None and number % 2 == 0:
            return True, "Disabled for even numbers"
        else:
            return False, "This is a toggle button"
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    

    NB. Since you want to disable the button when the input number is even, I inverted the return values for the button disabled property.


    If you don't want to use a wrapper, another way to fix this is to control the tooltip with a callback :

    The tooltip's visibility can be controlled with callbacks much like a Popover component. Simply set the desired value of is_open in a callback. If you are manually controlling the value of is_open, you may wish to also set trigger=None. By default the Tooltip will show when the target element is hovered or focused.