Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Bootstrap Rows + Columns With Dash

I’m using bootstrap CSS to create my layout. I imagine my approach is wrong as it takes lots of code to create nested div classes. Please let me know if their is a more appropriate way to build my layout. The code is below:

    html.Div(
    [
        html.Div(
            [
                html.H3(children='Facebook Overview'),
                html.P(children='Spend (Last 30 Days): $%.2f' % fb_total_spend),
                html.P(children='Spend (Yesterday): $%.2f' % fb_yesterday_spend),
            ],
            className="col-sm"
        ),
        html.Div(
            [
                html.H3(children='Adwords Overview'),
                html.P(children='Spend (Last 30 Days): $%.2f' % google_total_spend),
                html.P(children='Spend (Yesterday): $%.2f' % google_yesterday_spend),
            ],
            className="col-sm"
        ),
        html.Div(
            [
                html.H3(children='All Accounts Overview'),
                html.P(children='Spend (Last 30 Days): $%.2f' % total_30day_spend),
                html.P(children='Spend (Yesterday): $%.2f' % total_yesterday_spend),
            ],
            className="col-sm"
        ),
    ],
    className="row"
),

This example isn’t too bad, but it will quickly become a lot if I want to add more more bootstrap features to each column (such as cards or a jumbotron).

Thanks for writing in. Bootstrap and other CSS should work exactly the same in Dash as it would in any HTML (<div class='col-sm'></div> is the same as html.Div([], className='col-sm').

You’re on the right track, and I’ll leave it to other community members to offer more general advice on how they’ve dealt with bootstrap features.

The way I normally deal with this (especially when repeating layouts) is to create functions.
Something like this:

def spendCol(Header, P1, P2):
    div = html.Div([
        html.H3(Header),
        html.P(P1),
        html.P(P2)
        ], className="col-sm")
    return div

def row(children):
    return html.Div(children, className='row')

layout = row([
    spendCol('Facebook Overview',
             'Spend (Last 30 Days): $%.2f' % fb_total_spend,
             'Spend (Yesterday): $%.2f' % fb_yesterday_spend
             ),
    spendCol('Adwords Overview',
             'Spend (Last 30 Days): $%.2f' % google_total_spend,
             'Spend (Yesterday): $%.2f' % google_yesterday_spend
             ),
    spendCol('All Accounts Overview',
             'Spend (Last 30 Days): $%.2f' % total_30day_spend,
             'Spend (Yesterday): $%.2f' % total_yesterday_spend
             )
    ])
        

As you said this case isn’t too bad but you can see how this would help with repeated layouts with different content across multipage apps!

1 Like

As I mention in this reply, my strategy for managing Bootstrap classes is similar to @mikesmith1611 but more general. I use Row and Col functions that would allow me to write your code like this:

Row([
    Col([
        html.H3('Facebook Overview'),
        html.P('Spend (Last 30 Days): $%.2f' % fb_total_spend),
        html.P('Spend (Yesterday): $%.2f' % fb_yesterday_spend),
    ]),
    Col([
        html.H3('Adwords Overview'),
        html.P('Spend (Last 30 Days): $%.2f' % google_total_spend),
        html.P('Spend (Yesterday): $%.2f' % google_yesterday_spend),
    ]),
    Col([
        html.H3('All Accounts Overview'),
        html.P('Spend (Last 30 Days): $%.2f' % total_30day_spend),
        html.P('Spend (Yesterday): $%.2f' % total_yesterday_spend),
    ]),
])

(Note that you can pass the children keyword argument in without a name if it’s the first argument)

You could define Col and Row as simple functions that just wrap html.Divs or you could also make them a bit more intelligent in how they pass on kwargs etc into the inner components. I do a bit of that in this project. You can find the functions in components.py which make use of a decorator to help pass through arguments.

Thanks for the help guys! It really helped.