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

Strange connection between tabs with identical layouts

Hi,
I’ve been experiencing strange behavior when working with Tabs. After much troubleshooting, it seems that Dash has some weird things happening when you have two tabs with identical layouts. In my actual app, for instance, the callbacks stop working when I move from one tab, over to an identically-layed-out-tab, and then back to the original. When I click over to a unique Tab and then back to the original, the callback functionality returns. I’ve created a somewhat simple example to demonstrate what happens when two tabs have the same layouts (and a third does not)…see below. Can anyone shed light on this?

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

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

TAB1 = html.Div([
    dcc.Input(id='tab1_i', type='text'),
    html.Div(id='input_1')
])

TAB2 = html.Div([
    dcc.Input(id='tab2_i', type='text'),
    html.Div(id='input_2')
])

TAB3 = html.Div([
    html.Div("here is an extra piece of text that tabs 1 and 2 don't have! "
             "Besides this text, everything else is the same!"),
    dcc.Input(id='tab3_i', type='text'),
    html.Div(id='input_3')
])


def P(x):
    return html.P([x])

app.layout = html.Div([
    P("Type something in Tab 1 input, then move to Tab 2. Notice that the value passed to the callback"),
    P("in Tab 2 is refreshed to 'None', but the dcc.Input component still retains"),
    P("the text from Tab 1.  Now Click on Tab 3 and return to tab 2. Notice that"),
    P("the text clears properly (ie is blank)."),
    P("Now try the same thing Between Tabs 2 and 3, or 1 and 3. Notice that the whole behavior changes!"),
    P("Why is it that when the layouts for two tabs are identical, the new tab isn't rendered properly?"),
    dcc.Tabs(id='tab-selector', mobile_breakpoint=0, value='tab1', children=[
        dcc.Tab(label='Tab 1', value='tab1'),
        dcc.Tab(label='Tab 2', value='tab2'),
        dcc.Tab(label='Tab 3', value='tab3'),
    ]),
    html.Div(id='tab-content')
])


# Input bar in Tab 1
@app.callback(
    Output('input_1', 'children'),
    [Input('tab1_i', 'value')]
)
def update_output_div(input_value):
    return 'You\'ve entered "{}"'.format(input_value)

# Input bar in Tab 2
@app.callback(
    Output('input_2', 'children'),
    [Input('tab2_i', 'value')]
)
def update_output_div(input_value):
    return 'You\'ve entered "{}"'.format(input_value)

# Input bar in Tab 3
@app.callback(
    Output('input_3', 'children'),
    [Input('tab3_i', 'value')]
)
def update_output_div(input_value):
    return 'You\'ve entered "{}"'.format(input_value)

# Tab rendering callback
TABS = dict(zip(['tab1','tab2','tab3'], [TAB1, TAB2, TAB3]))
@app.callback(
    Output('tab-content', 'children'),
    [Input('tab-selector', 'value')]
)
def render_tab(selected_tab):
    return TABS[selected_tab]


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

Hm, that’s odd. It sounds like a bug. Would you mind creating an issue in https://github.com/plotly/dash-core-components/ and linking that issue to this thread?