Skip to content

feat: accessibility (a11y) support & improvements to the core interactive components#203

Open
Vinyl-Davyl wants to merge 6 commits intoNetflix:masterfrom
Vinyl-Davyl:feat/accessibility-improvements
Open

feat: accessibility (a11y) support & improvements to the core interactive components#203
Vinyl-Davyl wants to merge 6 commits intoNetflix:masterfrom
Vinyl-Davyl:feat/accessibility-improvements

Conversation

@Vinyl-Davyl
Copy link
Copy Markdown

@Vinyl-Davyl Vinyl-Davyl commented Apr 13, 2026

Requirements for a pull request

  • Unit tests related to the change have been updated
  • Documentation related to the change has been updated

Description of the Change

The metaflow-ui codebase currently has zero aria-* attributes, zero role attributes, and only 3 tabIndex usages across 124 components. This PR adds foundational accessibility (a11y) support to the core interactive components, bringing the UI closer to WCAG 2.1 AA compliance.

Changes by component

Component Improvement
Button Fixed tabIndex default from 99 to 0 — a value of 99 breaks natural keyboard tab order (WCAG 2.4.3)
Modal Added role="dialog", aria-modal="true", aria-label, focus trap (Tab/Shift+Tab cycles within the modal), and auto-focus on open
Dropdown Added full keyboard navigation: Arrow Up/Down to highlight options, Enter/Space to select, Enter/Space/ArrowDown to open when closed. Added aria-haspopup="listbox", aria-expanded, role="listbox", role="option", aria-selected
Notifications Added aria-live="polite" so screen readers announce notifications without interrupting the user
FullPageContainer Added role="button", aria-label="Close fullscreen", tabIndex={0} to close button (was not keyboard accessible)
Breadcrumb Added aria-label="Breadcrumb navigation" on the nav wrapper, role="button"/aria-label/tabIndex on the close button
DAGControlBar Added title attribute to fullscreen button for tooltip on hover

Alternate Designs

An alternative was to add ARIA attributes only to the Button component and let all consumers inherit them via props. This was rejected because many interactive elements (close icons, overlays) are plain divs that don't go through the Button component — they need direct ARIA attributes. The chosen approach targets each component individually for complete coverage of the interactive surface.

Possible Drawbacks

  • The Button tabIndex change from 99 to 0 affects every Button instance in the app. This is intentionally the correct default per WCAG — a value of 99 placed all buttons at the end of the tab order. Any component that explicitly passes a tabIndex prop is unaffected.
  • The Modal focus trap adds a keydown event listener when the modal is open. This is cleaned up on unmount via the useEffect return, so there is no risk of memory leaks.

Verification Process

  1. Ran npx tsc --noEmit — zero TypeScript errors
  2. Tested Modal: Tab and Shift+Tab cycle within the modal without escaping to the background. Escape closes it. The close button is reachable via keyboard.
  3. Tested Dropdown: Arrow Down opens the dropdown, Arrow Up/Down highlights options, Enter selects, Escape closes. Screen reader announces the listbox role.
  4. Verified Notifications aria-live="polite" by triggering a notification — screen reader (VoiceOver) announces the message without interrupting current focus.
  5. Verified all close buttons (Modal, FullPageContainer, Breadcrumb) are now focusable via Tab and activatable via Enter/Space.

Quick Preview of Metaflow UI Accessibility Improvements

Context Previous Accessibility Score New Accessibility Score
Accessibility Score Comparison Screenshot 2026-04-13 at 5 32 42 PM Screenshot 2026-04-13 at 6 11 51 PM

- Breadcrumb navigation (Home page + Run page)

Where: the breadcrumb bar at the top (shows "Home" and the Go to... input)

How to test:

  • The breadcrumb wrapper now has aria-label="Breadcrumb navigation"
  • Click a run (e.g. "BasicFlow / 3") to navigate to the run page
  • Click the breadcrumb path text to open the Go-to editor
  • The X close button on the right of the input is now keyboard-focusable (tabIndex=0, aria-label="Close navigation")
  • Press Tab to reach it, Enter to close
Screenshot 2026-04-12 at 9 11 40 PM Screenshot 2026-04-12 at 9 12 08 PM Screenshot 2026-04-13 at 4 44 41 PM ---

- Dropdown keyboard navigation (Run page → Timeline tab)

Where: URL click any run (e.g. BasicFlow / 3) → click Timeline tab → look at the dropdowns at the top: Mode (Workflow/Task), Order by (Started at), Group by step checkbox
How to test:

  1. Tab to the Mode dropdown (shows "Workflow")
  2. Press ArrowDown or Enter or Space → dropdown opens
  3. Press ArrowDown/ArrowUp → options highlight with background color
  4. Press Enter or Space → selects the highlighted option
  5. Press Escape → closes without selecting
Screenshot 2026-04-13 at 4 38 16 PM Screenshot 2026-04-13 at 4 42 29 PM

- Modal focus trap (Run page → Task page → Artifact Table)

Where: URL click BasicFlow / 3 → click Timeline tab → click a task (e.g. 520362) on the left → scroll down to see the Artifacts section → click an artifact value link to open the Modal

Note: The artifact table needs to be enabled. If it doesn't show, the feature flag ARTIFACT_TABLE is off by default. As an alternative, you can test the Modal via the mock setup. But the easier approach is below.
How to test:

  1. Click "Show fullscreen" → DAG opens in fullscreen
  2. Tab → the X close button in the top-right corner gets focus (it now has tabIndex={0}, aria-label="Close fullscreen")
  3. Press Enter → closes fullscreen
  4. Press Escape → also closes

- Notifications aria-live (Task page → copy logs)

Where: URL → click BasicFlow / 3 → click Timeline tab → click a task → scroll to the stdout log section → click the copy button (clipboard icon)
How to test:

  1. Click the copy icon button → a notification toast appears at the top-right: "All logs copied to clipboard"
  2. Inspect the notification wrapper in DevTools → show aria-live="polite" and aria-label="Notifications"
Screenshot 2026-04-13 at 4 52 24 PM Screenshot 2026-04-13 at 4 53 08 PM

Release Notes

Added accessibility support across core UI components: keyboard navigation for Dropdown, focus trapping in Modal, screen reader announcements for Notifications, and ARIA attributes throughout — bringing the UI closer to WCAG 2.1 AA compliance.

@Vinyl-Davyl
Copy link
Copy Markdown
Author

cc: @saikonen @romain-intel @npow

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant