Floating css modals for form options

Hi,

I have about 30 form options on an app which is quickly becoming unmanageable: the figure is beneath the fold, so it’s hard to see the results.

I was thinking about trying a floating css modal such as this: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_modal2

Before I get going, would this even work with Dash? And would the form options and callbacks still work if I put all the form stuff in the modal?

Thanks

Will

1 Like

Wow, that’s a pretty cool idea. In that example, the JS is just changing the style from display: none to display: block, which you could do in a dash callback with:

@app.callback(Output('modal', 'style'), [Input('button', 'n_clicks')])
def display_modal(n_clicks):
   if n_clicks % 2 == 0:
       return {'display': 'none'}
   else:
       return {'display': 'block'}

The callbacks will still work as usual since the elements are technical still “on the page” they’re just invisible ('display': 'none')

In the future, I imagine that we’ll have a formal “modal” component (or someone in the community will write one) that could be used a little bit more easily.

Another option would be to display all of the options in a left-sidebar and keep the graph on the right. That’s similar to what we do in the plotly chart editor

Didn’t think of that - good idea! Might be a lot simpler, and I may be able to steal your code too :slight_smile: I will never understand css…

If you’re using https://codepen.io/chriddyp/pen/bWLwgP, you should be able to make a simple sidebar layout like this with something like:

app.layout = html.Div([
    html.Div(className='row', children=[
         html.Div(className='four columns', children=[
              # your sidebar controls
         ]),
         html.Div(className='eight columns', children=[
              dcc.Graph(...)
         ])
    ])
])
1 Like

I fumbled together a working modal using CSS and the existing stuff. Not as clean as a javascript implementation of it (screen still scrolls and no animations) but it works.

# -*- coding: utf-8 -*-
import dash
import dash_html_components as html
from dash.dependencies import Input, Output, State, Event
import logging

def main():
    # Disable Flask's get/post console logs
    log = logging.getLogger('werkzeug')
    #log.disabled = True

    app = dash.Dash()
    app.config['suppress_callback_exceptions']=True
    app.scripts.config.serve_locally = True

    app.layout = html.Div(children=[
        html.Div([
            html.Button('Get', className="info-button", n_clicks=0, id='info-button'),
        ], className="info-button-div"),
        ##### DETAILED INFO MODAL ######
        html.Div([
            html.Div([
                html.Label('JUST SOME TEXT: ')
            ], className="text-div"),
            html.Div([
                html.Button('Close', className="close-button", n_clicks=0, id='close-button'),
            ], className="close-button-div"),
        ], className="modal-container", id="modal-container", style={'display': 'none'}),
        ##### MODAL BACKDROP ######
        html.Div([
        ], className="modal-backdrop", id="modal-backdrop", style={'display': 'none'}),
        html.Div(id='modal-button-values', children="Get:0 Close:0 last:Close", style={'display': 'none'}),
    ])

    ###########################
    ###### MODAL CONTROL ######
    ###########################

    @app.callback(Output('modal-button-values', 'children'),
        [Input('info-button', 'n_clicks'), Input('close-button', 'n_clicks')],
        [State('modal-button-values', 'children')],[])
    def modal_button_status(get_clicks, close_clicks, button_values):
        button_values = dict([i.split(':') for i in button_values.split(' ')])

        if get_clicks > int(button_values["Get"]):
            last_clicked = "Get"
        elif close_clicks > int(button_values["Close"]):
            last_clicked = "Close"
        else:
            last_clicked = "Close"

        return "Get:{0} Close:{1} last:{2}".format(get_clicks, close_clicks, last_clicked)

    @app.callback(Output('modal-container', 'style'),
        [Input('modal-button-values', 'children')],
        [],[])
    def modal_display_status(button_values):
        button_values = dict([i.split(':') for i in button_values.split(' ')])

        if button_values["last"] == 'Get':
            return {'display': 'inline'}
        else:
            return {'display': 'none'}

    @app.callback(Output('modal-backdrop', 'style'),
        [Input('modal-button-values', 'children')],
        [],[])
    def modal_backdrop_status(button_values):
        button_values = dict([i.split(':') for i in button_values.split(' ')])

        if button_values["last"] == 'Get':
            return {'display': 'inline'}
        else:
            return {'display': 'none'}

    external_css = ["https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css",
                    "https://fonts.googleapis.com/css?family=Raleway:400,400i,700,700i",
                    "https://codepen.io/cryptocss/pen/geyPdg.css",
                    "https://fonts.googleapis.com/css?family=Product+Sans:400,400i,700,700i",]

    for css in external_css:
        app.css.append_css({"external_url": css})

    app.run_server(debug=False)

if __name__ == '__main__':
    main()

CSS portion (also found in the codepen link:

.modal-container {
    opacity: 1;
    background-color: #fff;
    max-width: 400px;
    width: 400px;
    padding: 10px 30px;
    position: fixed;
    left: calc(50% - 200px);
    top: 12%;
    border-radius: 4px;
    z-index: 10001;
    pointer-events: auto;
    cursor: auto;
    visibility: visible;      
    box-shadow: 0 3px 7px rgba(0, 0, 0, 0.6);
}

.modal-container .close-button-div{
    float: right;
}

.modal-backdrop {
    background-color: rgba(0, 0, 0, 0.6);
    width: 100vw;
    height: 100vh;
    position: fixed;
    left: 0;
    top: 0;
    z-index: 10000;
    visibility: visible;      
}

There was also a javascript one that someone implemented here but I couldn’t figure out how to get working because I couldn’t figure out the custom packages for Dash. :\
https://github.com/StratoDem/sd-material-ui

Would be great to see the integration of some of these more commonly used web features as Dash Core Components.

I’m pretty new to dash and I am trying to implement a sidebar like the one that is in the plotly chart editor in my python dash project.

I want the same ability to add n traces with specific options. I love the look and feel of the sidebar in the plotly chart editor but I don’t want all the functionality of the chart editor, however.

Is it possible to use the same sidebar code from the chart editor in a dash app? How would I go about doing that?

Thanks.