Skip to content

fix(a11y): topbar logo and dark-mode toggle visible in HCM#10847

Open
bmatar wants to merge 1 commit intoswagger-api:masterfrom
bmatar:bug/7350-topbar-hcm-refinements
Open

fix(a11y): topbar logo and dark-mode toggle visible in HCM#10847
bmatar wants to merge 1 commit intoswagger-api:masterfrom
bmatar:bug/7350-topbar-hcm-refinements

Conversation

@bmatar
Copy link
Copy Markdown

@bmatar bmatar commented Apr 19, 2026

Description

In Windows High Contrast Mode (Edge / Chromium with forced-colors: active), the standalone topbar's Swagger logo wordmark and the dark-mode toggle's lightbulb icon both become invisible or near-invisible against the HCM-substituted Canvas. The logo wordmark paths use literal fill="#fff", and the dark-mode toggle SVG uses fill: #e4e6e6 — both preserved by Chromium's spec-correct default forced-color-adjust: preserve-parent-color for SVG. The dark-mode toggle wrapper also has opacity: 0.8, which composites multiplicatively and dims the icon further regardless of the path fill.

In HCM-light, the white logo wordmark is invisible on Canvas-white. In HCM-dark, the gray lightbulb sits at low contrast. The toggle button is operable (it has a focusable <button>) but sighted HCM users have no visible cue.

A new @media (forced-colors: active) block in _topbar.scss pins the logo wordmark paths to CanvasText and the dark-mode toggle SVG to ButtonText, both with forced-color-adjust: none, and resets the wrapper opacity to 1 so the system-color contrast guarantee isn't dimmed.

Motivation and Context

Part of the HCM accessibility backlog tracked in #7350; this PR fixes the standalone topbar surface specifically. Detected by Tactual. WCAG 1.4.11 Non-text Contrast.

How Has This Been Tested?

  • npm run test:unit — all suites pass (829 tests)
  • npm run build — clean
  • Local build served alongside an unfixed master build for direct side-by-side comparison
  • Per-element pixel diff across 8 mode combinations (page-mode × HCM-scheme × forced-colors-on/off), with state receipts asserting html.dark-mode and forced-colors: active at capture time. Topbar elements show diffs only in HCM scenarios; non-HCM scenarios are byte-identical
  • Manual verification with Microsoft Edge with OS-level High Contrast Mode enabled
  • Manual verification with NVDA — no regression in announced labels or focus order

Screenshots

Same swagger-ui commit on both ports, only this patch differing. The html.dark-mode class is irrelevant to the topbar surface in HCM (the OS substitutes Canvas/CanvasText regardless), so only the HCM scheme axis has distinct visual states.

HCM light:

BEFORE AFTER
topbar-hcm-light-before topbar-hcm-light-after

HCM dark:

BEFORE AFTER
topbar-hcm-dark-before topbar-hcm-dark-after

Out of scope

Checklist

My PR contains...

  • No code changes (src/ is unmodified: changes to documentation, CI, metadata, etc.)
  • Dependency changes (any modification to dependencies in package.json)
  • Bug fixes (non-breaking change which fixes an issue)
  • Improvements (misc. changes to existing features)
  • Features (non-breaking change which adds functionality)

My changes...

  • are breaking changes to a public API (config options, System API, major UI change, etc).
  • are breaking changes to a private API (Redux, component props, utility functions, etc.).
  • are breaking changes to a developer API (npm script behavior changes, new dev system dependencies, etc).
  • are not breaking changes.

Documentation

  • My changes do not require a change to the project documentation.
  • My changes require a change to the project documentation.
  • If yes to above: I have updated the documentation accordingly.

Automated tests

  • My changes can not or do not need to be tested.
  • My changes can and should be tested by unit and/or integration tests.
  • If yes to above: I have added tests to cover my changes.
  • If yes to above: I have taken care to cover edge cases in my tests.
  • All new and existing tests passed.

In Windows High Contrast Mode the standalone topbar Swagger logo and
the dark-mode toggle's lightbulb icon both become invisible or near-
invisible against the HCM-substituted Canvas. The logo's wordmark
paths use literal fill #fff which preserves under Chromium's default
forced-color-adjust: preserve-parent-color for SVG and disappears in
HCM light. The dark-mode toggle's SVG fill #e4e6e6 likewise preserves
and renders at low contrast in any HCM theme; the parent .dark-mode-
toggle also has opacity: 0.8, which composites multiplicatively and
dims the icon further.

A new @media (forced-colors: active) block in _topbar.scss pins the
logo wordmark paths to CanvasText and the dark-mode toggle SVG to
ButtonText with forced-color-adjust: none, and resets the parent
opacity to 1 so the system-color contrast guarantee isn't dimmed.
ButtonText/CanvasText are the system colors paired with ButtonFace/
Canvas and guarantee contrast in any user HCM theme.

Refs swagger-api#7350
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