Wrap dcc.Tabs over two lines

Hi DASH community

In an application we are using tabs (dcc.Tabs) to organize various views and it seems we would like to expand with more and more tabs (currently 12) to the point that it would be convenient if the row of tabs could wrap into two rows.

What would be the way to accomplish this? I could be OK with having fixed (permanently) two rows, but some ‘intelligence’ would be nice.

html.Div(dcc.Tabs(id=‘globaltab’,children=build_boxtabs(),style=tabs_style))

tabs_style = {
‘width’:‘100%’,
‘height’: ‘45px’
}

Is it recommended to use dbc.Row and dbc.Col to control the layout, like in this thread (from 2021):

Another (older 2019) thread about this subject:

With kind regards,
Claus

Hi, you could try adding this to the tabs_style {display’ : ‘flex’, ‘flex-wrap’ : ‘wrap’}. The idea is that a tab goes to the next line if it does not fit in the 100%.

1 Like

Thanks for the tip on flex-wrap. It does ‘something’ which is; text within a tab can spread over multiple lines. As I push my app further (narrower view), then tabs stays on one line, but the first tab takes up 100% of the view, and I get a scroll bar at the bottom. Things look a bit chaotic:

I might be able to live with this, but is there a way the tabs themselves could organize into two rows?

With knid regads,
Claus

Hi Claus, I think the flex-wrap should be one level higher in the hierarchy.

html.Div(dcc.Tabs(id=‘globaltab’,children=build_boxtabs(),style=tabs_style), style = {display’ : ‘flex’, ‘flex-wrap’ : ‘wrap’})
instead of adding it to tabs_style?

That’s probably not going to work either, than it ends up on the div level, where it should not be. Difficult to say what goes wrong, without having a look at the output code.

1 Like

You’re right, it does not work either. The tabs are now always ‘smashed’ to a fixed minimum size (not using the full width of the page), so the text inside the tab space is not always readable. The tabs (still) stay on one line., and like before when pushed too far, I can only see one tab + I get a scroll bar at the bottom. As time permits, I shall try to make a minimum piece of code.

The only thing I can think of without seeing some code or output is changing flex-wrap into flexWrap. I have this tendency of mixing up pure css and react style stuff.

1 Like

Yeah, you would think it’s css (flex-wrap). I tried the other option (flexwrap) placed in the styling of the tabs (not the div container). This doesn’t break anything. When I squeeze the app too much, again I get one tab per line, now the tabs shows up vertically - but mixed in with the app. As seen below:

There are no errors in the console. I can setup a zoom call to go over it (the app incl. the output).
If I can put it in writing here, I need help to understand what I need to do.

/Claus

I should add that I am currently using:

  • dash 2.18.2
  • dash-bootstrap-components 1.6.0
  • dash-core-components 2.0.0
  • dash-html-components 2.0.0
  • Flask 3.0.3
  • plotly 5.24.1

Just in case it matters.

/Claus

I am open to more input as to what could be wrong. Why do the tabs not wrap around? Could it be that the tabs are inside a html.Div or some other ‘construction’ that doesn’t allow flex-wrap?

Still working on this. The solution might be to ask a different question, i.e. not use the word ‘wrap’ but instead use the word ‘span’ and take a closer look at this thread on Stackoverflow:
https://stackoverflow.com/questions/68004138/plotly-dash-how-to-span-a-component-across-two-rows
/Claus

Hi

Below is the minimal code that I promised previously. This code works (!)

import dash
from dash import dcc, html

app = dash.Dash(__name__)

tabs_style = {
    'width' : '100%',
    'height' : '45px',
    'display' : 'flex',
    'flex-wrap' : 'wrap',
    'justify-content' : 'center'
}

tab_style = {
    'borderTop' : '1px solid #cccccc',
    'borderBottom' : '1px solid #cccccc',
    'backgroundColor' : '#FFFFFF',
    'padding' : '8px',
    'text-align' : 'center',
    'flex' : '1 1 30%'
}

tab_style_sel = {
    'borderTop' : '1px solid #cccccc',
    'borderBottom' : '1px solid #cccccc',
    'backgroundColor' : '#F0F2F4',
    'padding' : '8px'
}

app.layout = html.Div([
    dcc.Tabs(id="tabs-example", value='tab-1', children=[
        dcc.Tab(label='Tab One', value='tab-1', style=tab_style, selected_style=tab_style_sel),
        dcc.Tab(label='Tab Two', value='tab-2', style=tab_style, selected_style=tab_style_sel),
        dcc.Tab(label='Tab Three', value='tab-3', style=tab_style, selected_style=tab_style_sel),
        dcc.Tab(label='Tab Four', value='tab-4', style=tab_style, selected_style=tab_style_sel),
        dcc.Tab(label='Tab Five', value='tab-5', style=tab_style, selected_style=tab_style_sel),
        dcc.Tab(label='Tab Six', value='tab-6', style=tab_style, selected_style=tab_style_sel),
    ],style=tabs_style
    ),
    html.Div(id='tabs-content-example')
])

@app.callback(
    dash.dependencies.Output('tabs-content-example', 'children'),
    [dash.dependencies.Input('tabs-example', 'value')]
)
def render_content(tab):
    return html.Div([
        html.H3(f'Content of {tab}')
    ])

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

Credits: I used EDGE browser and the built-in Copilot proposed this code. I added the inline CSS myself (which is what makes the code work). From previous proposal, what was missing was the ‘flex’ style in the dcc.Tab commands. It is not sufficient to specify the flex in dcc.Tabs, one must also define it for dcc.Tab.

With kind regards,
Claus

1 Like

Hi DASH community

Above code works in the sense I get three tabs per row, so with 6 tabs there will be two rows.

In my app there currently are 13 tabs and let’s say I’d like 9 tabs per row, then the second row will have 4 tabs. These 4 tabs will fill the whole width, which looks weird.

The following tab_style setting would allow for 9 tabs : ‘flex’ : ‘1 1 11%’ - the default settings are 0 1 auto. These three settings are short for flex-grow, flex-shrink and flex-basis as per these instructions: CSS flex property

When using flex-grow = 0, I did not get the expected result. All tabs on one line only, and no second row, unless they organize entirely vertical. Strange.

Also, the minimum code shows that the second row of tabs collide with the text below. If I set the height of the html.Div container, this doesn’t change anything.

Any help is highly appreciated.

With kind regards,
Claus

Still looking for answers and helpl is appreciated. The current issues means the code cannot be used for real-life application.

With this code:

Summary

import dash
from dash import dcc, html

app = dash.Dash(name)

tabs_style = {
‘width’ : ‘100%’,
‘display’ : ‘flex’,
‘flexWrap’ : ‘wrap’,
‘justifyContent’ : ‘flex-start’
}

tab_style = {
‘borderTop’ : ‘1px solid #cccccc’,
‘borderBottom’ : ‘1px solid #cccccc’,
‘backgroundColor’ : ‘#FFFFFF’,
‘padding’ : ‘8px’,
‘textAalign’ : ‘center’,
‘flex’ : ‘1 1 11%’,
‘flexBasis’: ‘11%’,
‘flexGrow’: 0

}

tab_style_sel = {
‘borderTop’ : ‘1px solid #cccccc’,
‘borderBottom’ : ‘1px solid #cccccc’,
‘backgroundColor’ : ‘#F0F2F4’,
‘padding’ : ‘8px’,
}

app.layout = html.Div([
dcc.Tabs(id=“tabs-example”, value=‘tab-1’, children=[
dcc.Tab(label=‘Tab One’, value=‘tab-1’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab Two’, value=‘tab-2’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab Three’, value=‘tab-3’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab Four’, value=‘tab-4’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab Five’, value=‘tab-5’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab Six’, value=‘tab-6’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 7’, value=‘tab-7’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 8’, value=‘tab-8’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 9’, value=‘tab-9’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 10’, value=‘tab-10’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 11’, value=‘tab-11’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 12’, value=‘tab-12’, style=tab_style, selected_style=tab_style_sel),
dcc.Tab(label=‘Tab 13’, value=‘tab-13’, style=tab_style, selected_style=tab_style_sel),
],style=tabs_style
),
html.Div(id=‘tabs-content-example’)
])

@app.callback(
dash.dependencies.Output(‘tabs-content-example’, ‘children’),
[dash.dependencies.Input(‘tabs-example’, ‘value’)]
)
def render_content(tab):
return html.Div([
html.H3(f’Content of {tab}')
])

if name == ‘main’:
app.run_server(debug=True)

I get this result, with always having “Content of div”, below the tabs and the second row not filling up all the space of row 2.