Black Lives Matter. Please consider donating to Black Girls Code today.

Tabs and dash_bootstrap_components.Toast

I have created tabbed layout for my Dash app:

import dash
import dash_table
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc



TAB_LAYOUT = html.Div([
    dcc.Tabs(id="tabs-main", value='tab-intro', children=[
        dcc.Tab(label='Introduction', value='tab-intro'),
        dcc.Tab(label='Your Files', value='tab-files'),
        dcc.Tab(label='Basic', value='tab-basic'),
...

app.layout = html.Div([
    TAB_LAYOUT,
...


# Top tabs callback
@app.callback(Output('tabs-content', 'children'),
              [Input('tabs-main', 'value')])
def render_content(tab):
    if tab == 'tab-intro':
        return tab_intro_layout
    elif tab == 'tab-basic':
        return tab_basic_layout
    elif tab == 'tab-files':
        return tab_files_layout
    ...

Now, on ‘files’ tab I have a file upload component and on successful operation on a file (adding, removing) I have a dbc.Toast reporting result of the operation:

# files - update files table
@app.callback(
    [
        Output(component_id='upload-error-modal', component_property='style'),
        Output(component_id='upload-error-message', component_property='children'),
        Output(component_id='files-table', component_property='data'),
        Output(component_id='toast-div', component_property='children'),
        Output(component_id='upload-wait-div', component_property='children')
    ],
    [
        Input('session-id', 'children'),
        Input('upload-data', 'contents'),
        Input('upload-error-close-button', 'n_clicks'),
        Input('files-table', 'data_previous')
    ],
    [
        State('upload-data', 'filename'),
        State('files-table', 'data')
    ]
)
def update_files_table(session_id, upload_data_contents, error_close_button_nclicks,
                           data_previous, filename, data):
...
        if removed_filename:
            return {'display': 'none'}, '', data, make_toast_file_op(removed_filename, 'File removed.'), filename



def make_toast_file_op(filename, message):
    return dbc.Toast([html.P(filename, className="mb-0")],
                     header=message,
                     className='toast',
                     headerClassName='toast-header',
                     bodyClassName='toast-body',
                     duration=3500)

Now on file upload or removal a Toast is displayed and it vanishes after 3.5s.

However, if I switch to another tab, say tab-basic before a Toast vanishes, it seems like a wrong layout is updated and this results in error:

An object was provided as `children` instead of a component, string, or number (or list of those). Check the children property that looks something like:

As long as I do not switch to another tab and wait until the Toast disappears, there’s no error.

The detailed error message seems to indicate that it is indeed layout of tab-basic (when I switched to that tab to get the error) and not the layout of tab-files.

How can I fix that?

What if you make the Toast components children of your page layout vice children of a particular Tab?

app.layout = html.Div([
    TAB_LAYOUT,
    TOAST_LAYOUT,
...
1 Like

Nice idea, but the Toast does not show up now at all…

My bad, I just positioned Toast way too low down the page somehow, it was showing up there.

2 Likes