`st.dataframe` toolbar stays invisible (opacity 0) while its buttons have keyboard focus · Issue #17337 · streamlit/streamlit · GitHub
Skip to content

st.dataframe toolbar stays invisible (opacity 0) while its buttons have keyboard focus #17337

Open

Description

@jhutchin

Checklist

  • I have searched the existing issues for similar issues.
  • I added a very descriptive title to this issue.
  • I have provided sufficient information below to help reproduce this issue.

Summary

The element toolbar above an st.dataframe (Show/hide columns, Download as CSV, Search, Fullscreen) is in the Tab order, but [data-testid="stElementToolbar"] keeps opacity: 0 while one of its buttons has keyboard focus. It only becomes visible on mouse hover. A keyboard user therefore tabs through four buttons they cannot see, which fails WCAG 2.4.7 (Focus Visible).

Related but distinct: #13332 (keyboard access to the column-header menu) and #17127 (toolbar target size, fixed).

Reproducible Code Example

import pandas as pd
import streamlit as st


def home():
    st.title("Home")
    st.button("First button")
    st.dataframe(pd.DataFrame({"a": [1, 2, 3], "b": ["x", "y", "z"]}))
    st.button("Last button")


pg = st.navigation(
    {
        "": [st.Page(home, title="Home")],
        "Group": [
            st.Page(lambda: st.write("B"), title="Page B", url_path="b"),
            st.Page(lambda: st.write("C"), title="Page C", url_path="c"),
        ],
    },
    position="top",
)
pg.run()

Steps To Reproduce

  1. Run the app above.
  2. Click the page background, then press Tab until focus passes "First button".

Expected Behavior

The toolbar is visible whenever focus is inside it, as it is on hover.

Current Behavior

The next four Tab stops are the toolbar buttons. document.activeElement is the button, and getComputedStyle(toolbar).opacity is "0" for all four.

Is this a regression?

  • Yes, this used to work in a previous version.

Debug info

  • Streamlit version: 1.65.0 (also reproduced on 1.61.1)
  • Python version: 3.11
  • Operating System: Linux (RHEL 8)
  • Browser: Chromium (headless, Playwright 1.63.0)

Additional Information

Workaround we use in our app:

[data-testid="stElementToolbar"]:focus-within { opacity: 1; }

Activity

  1. added
    ai-reviewIf applied to PR or issue will run AI review workflow
    on Oct 8, 2026
  2. added
    type:bugSomething isn't working as expected
    area:frontendRelated to frontend aspects
    area:accessibilityRelated to accessibility (a11y) compliance
    and removed
    ai-reviewIf applied to PR or issue will run AI review workflow
    on Oct 8, 2026
  3. github-actions commented on Oct 8, 2026

    @github-actions
    Contributor

    This is an accessibility bug in the shared element toolbar (data-testid="stElementToolbar"): on st.dataframe, Show/hide columns, Download as CSV, Search, and Fullscreen stay in the tab order while the toolbar remains at opacity: 0, so keyboard users get no visible control or focus indicator (WCAG 2.4.7). The report covers 1.61.1 and 1.65.0 and does not describe a regression.

    In frontend/lib/src/components/shared/Toolbar/styled-components.ts, an unlocked StyledToolbarWrapper sets opacity: 0 and top: -1rem, then reveals itself only for &:hover, &:active, and &:focus-visible (and those same states on the parent target). The wrapper div is not focusable; Tab moves focus to the inner <button>, and :focus-visible matches only the focused element, so those reveal rules never run. Hover and press still show the toolbar because :hover and :active match the wrapper. st.code and the dataframe markdown-cell toolbar already stay visible via :focus-within / :focus-within:has(:focus-visible); the shared toolbar needs that selector as well, including the top offset the hover rule applies. st.data_editor uses this same dataframe toolbar, and the shared Toolbar is also used by images, charts, and st.audio_input.

    Related Issues

    • #13332 — Open request to make the dataframe column-header overflow menu keyboard accessible. Same dataframe chrome, separate control: that menu never receives focus, while this toolbar does receive focus and stays invisible.
    • #17127 — Closed. The same dataframe toolbar buttons failed WCAG 2.2 target size (22.4px) and were fixed separately. This report is focus visibility (WCAG 2.4.7).
    • #16148 — Open. Fullscreen buttons on this shared toolbar share one accessible name, so screen readers cannot tell which element they control. Same buttons, with a naming failure alongside this visibility failure.

    This is an automated triage comment using grok-4.7-xhigh. Please verify the suggested labels and related issues.

  4. added
    type:enhancementRequests for feature enhancements or new features
    and removed
    type:bugSomething isn't working as expected
    on Oct 8, 2026
  5. github-actions commented on Oct 8, 2026

    @github-actions
    Contributor

    To help Streamlit prioritize this feature, react with a 👍 (thumbs up emoji) to the initial post.

    Your vote helps us identify which enhancements matter most to our users.

    Views

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessibilityRelated to accessibility (a11y) compliancearea:frontendRelated to frontend aspectsfeature:st.data_editorRelated to the `st.data_editor` widgetfeature:st.dataframeRelated to the `st.dataframe` elementtype:enhancementRequests for feature enhancements or new features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions