Skip to content

fix(a11y): WCAG 2.4.1 — add SkipLink component for keyboard bypass blocks#39240

Open
Aitema-gmbh wants to merge 2 commits intoapache:masterfrom
Aitema-gmbh:fix/wcag-2.4.1-bypass-blocks
Open

fix(a11y): WCAG 2.4.1 — add SkipLink component for keyboard bypass blocks#39240
Aitema-gmbh wants to merge 2 commits intoapache:masterfrom
Aitema-gmbh:fix/wcag-2.4.1-bypass-blocks

Conversation

@Aitema-gmbh
Copy link
Copy Markdown

SUMMARY

Implements WCAG 2.1 criterion 2.4.1 (Bypass Blocks, Level A).

  • Add new SkipLink component in src/components/Accessibility/
  • Renders a visually hidden "Skip to main content" link that becomes visible on focus
  • Allows keyboard users to skip repetitive navigation and jump directly to main content
  • Uses temporary tabindex on target for reliable focus management

TESTING INSTRUCTIONS

  1. Open any page and press Tab → "Skip to main content" link should appear
  2. Press Enter → focus should jump to main content area
  3. Link should be invisible until focused

ADDITIONAL INFORMATION

@dosubot dosubot bot added change:frontend Requires changing the frontend design:accessibility Related to accessibility standards labels Apr 9, 2026
}

const SkipLink: FC<SkipLinkProps> = ({
targetId = 'main-content',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The default anchor target is main-content, but that ID does not exist in the current frontend/templates, so using this component without a custom targetId will not move focus to real main content. Point the default to an existing stable container ID so the skip link works out of the box. [logic error]

Severity Level: Major ⚠️
- ⚠️ Global "Skip to main content" link focus stays on link.
- ⚠️ WCAG 2.4.1 bypass blocks unmet in SPA layout.
- ⚠️ Keyboard users cannot reliably jump past navigation.
Suggested change
targetId = 'main-content',
targetId = 'app',
Steps of Reproduction ✅
1. Note that the SPA root element is defined in the server template at
`superset/templates/superset/spa.html:10` as `<div id="app" data-bootstrap="{{
bootstrap_data }}">`, and a repo-wide search (`Grep id=["']main-content["']`) shows no
element with `id="main-content"` anywhere in the codebase.

2. The React application mounts into this `#app` container from
`superset-frontend/src/views/index.tsx:6-14`, where `const appMountPoint =
document.getElementById('app');` and `ReactDOM.render(<App />, appMountPoint);` render
`App` into that root.

3. The global layout for all frontend routes is defined in
`superset-frontend/src/views/App.tsx:73-110`, which renders `<Menu />`, `<Layout>`, and
`<Layout.Content>` but does not assign `id="main-content"` (or any other matching ID) to
the main content container; there is currently no matching DOM node for the default
`targetId`.

4. When a developer uses the new `SkipLink` component with its default props anywhere
inside the SPA (for example, adding `<SkipLink />` at the top of the layout in `App.tsx`),
the click handler at `SkipLink.tsx:65-85` executes `document.getElementById(targetId)`
with `targetId = 'main-content'`, receives `null` (because no such element exists), and
falls into the `else` branch which only sets `window.location.hash = '#main-content'`. As
a result, pressing Enter on the "Skip to main content" link does not move focus to any
real main content container, so the skip link silently fails to fulfill its intended
bypass behavior in the current SPA structure unless callers always override `targetId` or
introduce a matching `id="main-content"` element.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/components/Accessibility/SkipLink.tsx
**Line:** 62:62
**Comment:**
	*Logic Error: The default anchor target is `main-content`, but that ID does not exist in the current frontend/templates, so using this component without a custom `targetId` will not move focus to real main content. Point the default to an existing stable container ID so the skip link works out of the box.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

* specific language governing permissions and limitations
* under the License.
*/
export { default as SkipLink } from './SkipLink';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Architect Review — HIGH

SkipLink is exported but never rendered in any application shell or layout, so the "Skip to main content" link never appears on real pages and keyboard users cannot bypass navigation.

Suggestion: Render SkipLink at the top of the global layout(s) or app shell, before navigation, so it is the first tabbable element across SPA and menu-only entrypoints.

Copy link
Copy Markdown
Contributor

@bito-code-review bito-code-review bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #a778cb

Actionable Suggestions - 1
  • superset-frontend/src/components/Accessibility/SkipLink.tsx - 1
    • Missing translation for default text · Line 63-63
Review Details
  • Files reviewed - 3 · Commit Range: 16d6282..806c8b2
    • superset-frontend/src/components/Accessibility/SkipLink.tsx
    • superset-frontend/src/components/Accessibility/index.tsx
    • superset-frontend/src/views/App.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo


const SkipLink: FC<SkipLinkProps> = ({
targetId = 'main-content',
children = 'Skip to main content',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing translation for default text

Import the translation function t from @superset-ui/core and change the default children value to t('Skip to main content') to enable internationalization.

Code Review Run #a778cb


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

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

Labels

change:frontend Requires changing the frontend design:accessibility Related to accessibility standards size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant