Dash - Adjust grid layout dynamically based on datatable width?

I have a reasonably complex multi-tab dash app. One tab is composed of ten discrete dash datatables. Depending on a dropdown selection, each datatable can have from three to eleven data columns (each datatable will have the same number of columns). I am using the grid system from the dash oil and gas example ( https://github.com/plotly/dash-oil-and-gas-demo/blob/master/assets/s1.css). Currently, each datatable is hardcoded to be six columns wide, two tables to a row. e.g.:

  html.Div(
      [
          html.Div(
              [
                  html.Label('Table 16a', style=label_style),
                  html.Div(id='table-16a')
              ],
              className = "pretty_container six columns"
          ),
          html.Div(
              [
                  html.Label('Table 16b', style=label_style),
                  html.Div(id='table-16b')
              ],
              className = "pretty_container six columns"
          ),
      ],
      className = "bare_container twelve columns",
      id = "table-container-16ab",
  ),

While this is acceptable with 3 data column or even 5 data column datatables, it starts to get squished at 7, 9, and 11 data columns. What I would like to do is to be able to do something like adjust the ā€˜className’ dynamically depending on the number of columns in each datatable dataframe. Something like:

  1. 3 columns in dataframe - className = ā€œpretty_container five columnsā€ [two tables per row]
  2. 5-7 columns in dataframe - className = ā€œpretty_container six columnsā€ [two tables per row]
  3. 9-11 columns in dataframe - className = ā€œpretty_container ten columnsā€ [ONE table per row]

Although I realize that it’s a little more complicated than simply dynamically adjusting className as we are now talking about dynamically adjusting the number of tables on a row. I attempted to do this by making className a global variable (className = class_name) and adjusting it in the callback, but the layout would only read the variable classname on initial load of the app, it would not adjust the className variable based on the callback output.

I am not married to my current system and would happily try a different method entirely if I could get this functionality. Any suggestions? CSS is not my strong suit.

I would either switch to the Bootstrap grid system (Grid system Ā· Bootstrap v5.2) or the Dash Mantine Components SimpleGrid:

I’d say that the DMC SimpleGrid is easier if you don’t want to handle all the CSS stuff. Create a SimpleGrid like that:

dmc.SimpleGrid(
    cols=2,
    children=[
        html.Div("Table 1"),
        html.Div("Table 2"),
        html.Div("Table 3"),
        html.Div("Table 4"),
        html.Div("Table 5"),
        html.Div("Table 6"),
        html.Div("Table 7"),
        html.Div("Table 8"),
        html.Div("Table 9"),
        html.Div("Table 10")
    ],
    id="simple_grid"
)

By setting the cols property, you can define how many children should be placed per row. This value can be modified with a callback. So if you have 9-11 columns in your dataframe, return cols=1 in your callback, e.g.:

@callback(
    Output("simple_grid", "cols"),
    Input("id_that_triggers_this_callback", "value")
)
def resize_grid(value):
    if value >= 9
        return 1
    return 2

The children of the dmc.SimpleGrid component will automatically fill the whole width. This means you can’t distinguish between 5 out of 12 columns or 6 out of 12 columns. You can see this behaviour on the dmc.SimpleGrid documentation in the ā€œSimple Usageā€ section.

If you want to control how many of the 12 columns each table should take, you can use dmc.Grid. On the dmc.Col component, you can use the span property to define how many columns out of 12 each dmc.Col can use. But this will require you to define 10 Outputs in your callback to target every dmc.Col separately.

1 Like