dbc.Tabs keyboard focus (accessibility)

I have a question very similar to dcc.Tab keyboard navigation (accesibility requirements)

Now I want to use dash bootstrap components (dbc.Tabs specifically), and the goal is to let users press the “Tab” button on keyboard to go to “Tab 2” for the purpose of accessibility standard compliance.

import dash
import dash_bootstrap_components as dbc
from dash import Input, Output, html

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LITERA])
server = app.server

app.layout = dbc.Container(
    [
dbc.Input(id="input-top", type="text", value="input top"),
        dbc.Tabs(
            [
                dbc.Tab(label="Tab 1", tab_id="tab-1",children=[
                        dbc.Container([
                            dbc.Row([
                                 dbc.Input(id="input-tab1", type="text", value="input Tab 1"),
                            ])
                ])
                ]),
                dbc.Tab(label="Tab 2", tab_id="tab-2", children=[
                        dbc.Container([
                            html.A(tabIndex= "0"),
                            dbc.Row([
                                 #html.Div(tabIndex="0"),
                                 dbc.Input(id="input-tab2", type="text", value="input Tab 2"),
                            ])
                ])
                ]),
            ],
            id="tabs",
            active_tab="tab-1",
        ),
        html.Div(id="content"),
        
    ]
)

@app.callback(Output("content", "children"), [Input("tabs", "active_tab")])
def switch_tab(at):
    if at == "tab-1":
        return "tab-1 clicked"
    elif at == "tab-2":
        return "tab-2 clicked"

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

If you run the app, when pressing tab on keyboard, “Tab 2” is not focused. By inspecting the elements, I located the html tag in question: <a role="tab" id="react-aria6745030723-2-tab-null" aria-controls="react-aria6745030723-2-tabpane-null" tabindex="-1" class="nav-link" style="cursor: pointer;">Tab 2</a>
And I see that tabindex was set to -1 (by dbc by default? i’m not sure). I tried inserting html.A(tabIndex= “0”) under Tab 2 in layout, but this doesn’t work. I believe the question might boil down to: How do I overwrite the attribute info in that tag?

Hello @wtc,

Have you tried setting the style of the Tab itself to tabindex=0?

Thank you. No, I haven’t. Do you mean using a separate CSS file? But can I do this, given that tabindex is not part of style?

Nope, I mean directly from the python code:

tab_style (dict ; optional): Defines CSS styles which will override styles previously set. The styles set here apply to the NavItem in the tab

https://dash-bootstrap-components.opensource.faculty.ai/docs/components/tabs/

I tried like this, but it doesn’t work:

 dbc.Tab(label="Tab 2", tab_id="tab-2",
                        tab_style={"tabindex": "0"},

Hmm, indeed.

Here, use a clientside callback:

import dash
import dash_bootstrap_components as dbc
from dash import Input, Output, html

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LITERA])
server = app.server

app.layout = dbc.Container(
    [
        dbc.Input(id="input-top", type="text", value="input top"),
        dbc.Tabs(
            [
                dbc.Tab(label="Tab 1", tab_id="tab-1", children=[
                    dbc.Container([
                        dbc.Row([
                            dbc.Input(id="input-tab1", type="text", value="input Tab 1"),
                        ])
                    ])
                ]),
                dbc.Tab(label="Tab 2", tab_id="tab-2", children=[
                    dbc.Container([
                        html.A(tabIndex="0"),
                        dbc.Row([
                            # html.Div(tabIndex="0"),
                            dbc.Input(id="input-tab2", type="text", value="input Tab 2"),
                        ])
                    ])
                ]),
            ],
            id="tabs",
            active_tab="tab-1",
        ),
        html.Div(id="content"),

    ]
)


@app.callback(Output("content", "children"), [Input("tabs", "active_tab")])
def switch_tab(at):
    if at == "tab-1":
        return "tab-1 clicked"
    elif at == "tab-2":
        return "tab-2 clicked"

app.clientside_callback(
    """function (id) {
        tabs = document.querySelectorAll("#" + id + " .nav-item a")
        tabs.forEach((tab) => {
            tab.tabIndex = 0
        })
        return window.dash_clientside.no_update
    }""",
    Output('tabs', 'id'), Input('tabs', 'id')
)


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

Have fun. :smiley: