Why does hide/show trick not work on more complex components?

I use the trick of setting the style of components to {‘display’: ‘none’}/{‘display’: ‘block’} to hide/show them. It works fine for simple things but fails for others. Is there a better way to do this? In my example below when clicking on the hide switch, you can see that there is no style to begin with and the rows look like I want them to. When I try to show it again using {‘display’: ‘block’} the row does not look right. When I use style = None it does. The problem with style = None is that there may be other style elements to begin with that I want to preserve and that is why I only change the ‘display’ of the style if style is not None.

"""Minimal dash program."""

from dash import callback, Dash, dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
import json

DO_NOT_DISPLAY_STYLE = {'display': 'none'}
DISPLAY_STYLE = {'display': 'block'}

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container([dbc.Row(dmc.Switch(id='hide-switch', size='lg', checked=False, label='hide')),
                            dbc.Row([dbc.Col([dbc.Row(dbc.Label('Type')),
                                              dbc.Row(dbc.Col(dcc.Dropdown(id='cp-new-key-type',
                                                                           options=['str',
                                                                                    'int',
                                                                                    'float',
                                                                                    'bool'],
                                                                           value='int')))]),
                                    dbc.Col(dbc.Row([dbc.Col([dbc.Row(dmc.Switch(id="cp-key-min",
                                                                                 size='lg',
                                                                                 checked=False,
                                                                                 label='Min')),
                                                              dbc.Row(dbc.Input(id="cp-new-key-min",
                                                                                type='number',
                                                                                value=None,
                                                                                placeholder='none'))])]))],
                                    id='hide-row'),
                            html.Div('', id='msg'),
                            dbc.Row([dbc.Col([dbc.Row(dbc.Label('Type')),
                                              dbc.Row(dbc.Col(dcc.Dropdown(id='cp-new-key-type2',
                                                                           options=['str',
                                                                                    'int',
                                                                                    'float',
                                                                                    'bool'],
                                                                           value='int')))]),
                                    dbc.Col(dbc.Row([dbc.Col([dbc.Row(dmc.Switch(id="cp-key-min2",
                                                                                 size='lg',
                                                                                 checked=False,
                                                                                 label='Min')),
                                                              dbc.Row(dbc.Input(id="cp-new-key-min2",
                                                                                type='number',
                                                                                value=None,
                                                                                placeholder='none'))])]))],
                                    id='hide-row2'),
                            html.Div('', id='msg2')])

@callback(Output('hide-row', 'style'),
          Output('hide-row2', 'style'),
          Output('msg', 'children'),
          Output('msg2', 'children'),
          Input('hide-switch', 'checked'),
          State('hide-row', 'style'),
          State('hide-row2', 'style'),
          prevent_initial_call=True)
def hide_row(hide, input_style, input_style2):
    """Hide/unhide the row."""
    if hide:
        if input_style is not None:
            ret_hide = input_style.copy()
            ret_hide['display'] = 'none'
        else:
            ret_hide = DO_NOT_DISPLAY_STYLE
        ret_hide2 = DO_NOT_DISPLAY_STYLE
    else:
        if input_style is not None:
            ret_hide = input_style.copy()
            ret_hide['display'] = 'block'
        else:
            ret_hide = DISPLAY_STYLE
        ret_hide2 = None


    ret_in_style = f"in style: {json.dumps(input_style) if input_style is not None else 'None'}"
    ret_out_style = f"out style: {json.dumps(ret_hide)}"
    ret_in_style2 = f"in style2: {json.dumps(input_style2) if input_style2 is not None else 'None'}"
    ret_out_style2 = f"out style2: {json.dumps(ret_hide2) if ret_hide2 is not None else 'None'}"

    return ret_hide, ret_hide2, f"{ret_in_style}, {ret_out_style}", f"{ret_in_style2}, {ret_out_style2}"


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

Hello @Brent,

Your app seems to work fine for me. You are probably conflicting with the different styles in the style sheet. !important can help with that.

For me, I use a dedicated class, you can experiment with a className of hidden and in your css:

.hidden {
    display: none !important
}

This will keep you from having to manipulate the style directly.

Another thing, if you want to change a specific key in data, like a dictionary, you can use set_props instead, this way you dont need to be concerned about pulling the current state of the object and simplifies your response.

2 Likes

Maybe I have different versions of things. I am still on a back level of dash because I have not had the time to make my huge app work with newer versions of dash I am on dash 2.15.0. Here is what it looks like to me after hiding and unhiding. Notice the top row spreads out to multiple rows.

Using the className trick will help you out, right now you are manipulating the display value and changing to block will make it take up a larger chunk of the window.

With the className it will only alter when it has that className and you wont need to reset it.

I highly recommend bumping to version 3+ of Dash, there was a performance boost for many. :slight_smile:

1 Like

Another thing to try, use {'display': 'flex'} instead of {'display': 'block'}

The {'display': 'block'} breaks the way the rows and columns work.

Yes, indeed {‘display’: ‘flex’} does work better than {‘display’: ‘block’} for this particular example. However, when mixing dbc.Row/Col and dcc.Dropdown like I do in other places, ‘flex’ does not render correctly. I was just using ‘block’/’none’ because that is what many people show as the way to hide/show.

Thanks

I’m not sure how I would use the .hidden class to accomplish what I am trying to do? What I am trying to do is show/hide particular elements depending on the state. Is set_props available in 2.15.0? I know I need to upgrade a lot of packages but I have them frozen for now because upgrading broke several things and I do not have time to find all of the breakages and fix them right now. Dash, ag-grid, mantine, numpy, pandas, sqlalchemy all have had some kind of issues playing nice with each other during my app development so I had to freeze the versions and wait for fixes in the packages. I think all of the fixes are in the packages now but it will be a big effort to upgrade them all and fix whatever breaks along the way. The last time I tried to upgrade dash to 3.x it did not work at all.