Repository navigation
Conversation
Forced colors repaints every author background-color that is not a system color as Canvas, so icons drawn with mask-image + background-color, state fills, and marker bars paint Canvas on Canvas and disappear. System colors are kept, so each now gets one inside @media (forced-colors: active): - Accordion: chevron in ButtonText; hide the USWDS +/-, which shares ::before with the focus ring and vanished on focus - Site alert and .usa-error-message icons: CanvasText - Checked checkbox: Highlight fill with the check cut out, so it shows on light and dark themes; disabled + checked uses GrayText - Checkbox and radio: keep the USWDS high-contrast box outline on focus - Text input, textarea, select: limit `outline: none !important` to normal mode so the global focus outline paints - Side and in-page nav current-page bar: Highlight Default rendering is unchanged. Adds a Chromium forced-colors regression test, and adds the forced-colors step to the mask-icon recipe in COMPONENTS.md. Refs nasa#229
7 of 11 tasks
abbybowman
self-requested a review
October 7, 2026 15:33
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Fixes the #229 items that don't have a PR yet: accordion, site alert, error message, checkbox, text field and side nav. While testing I found two more problems of the same kind and fixed them too: a checked checkbox looks unchecked on light themes, and the radio's circle disappears on focus. Radio selection (#232), the external link arrow (#234) and table sort (#252) are left to their own PRs. This branch merges cleanly with all three.
Refs #229
The cause is the same everywhere. In forced colors the browser repaints any
background-colorthat isn't a system color asCanvas(keeping only its alpha) and dropsbox-shadow. An icon drawn withmask-imageand a palette color ends up Canvas on Canvas. A system color set in author CSS is kept, and the mask still paints (checked in Chromium 153), so each fix is a system color inside@media (forced-colors: active).forced-color-adjust: noneisn't needed.::before, which the focus ring also uses, so it vanished on focusButtonText; USWDS +/- hidden in forced colorsCanvasTextCanvasTextoutline: noneremoved the USWDS high-contrast outline, which is the only thing drawing the box$border-high-contraston focusHighlightfill with the check cut out (mask-composite: exclude), like a native checkbox. Disabled + checked usesGrayTextoutline: none !importantleft a 1px → 2px border change as the only focus cuenot (forced-colors: active), as pagination does since #230, so the global focus outline paintsCanvasTextline, so it reads as a gapHighlight, set in the sharedhds-vertical-nav-linksmixinPlease confirm these calls:
Highlightrather thanSelectedItem. In Chromium's forced-colors emulation,SelectedItemstays#b3d7ffon both the light and dark palettes (1.4:1 on white), whileHighlightfollows the palette. This may matter for fix(form): preserve radio selection in forced colors #232, which usesSelectedItem.Type of change
How to review
Turn on forced colors (a Windows contrast theme, or DevTools > Rendering > Emulate CSS media feature
forced-colors: active) and check one light and one dark theme:With forced colors off, nothing should change.
Before requesting review
npm run lint,npm run format, andnpm testpass locallyIf your change affects how anything renders (styles, tokens, story markup, icons, or fonts):
If your change ships in the package (styles, tokens, or
src/assets/**):npx changeset) at the semver rubric levelnpm run check:api-snapshot; no driftNotes for reviewers
Testing:
scripts/forced-colors/__tests__/icons-and-states.test.js. It renders the markup against the compiled Sass in Chromium with forced colors on, light and dark, and checks that each indicator paints something other than Canvas or draws an outline. It also checks that the media query matched and the HDS CSS loaded. All 26 cases fail onmainfor the expected reason and pass on this branch.mainall 260 paint as Canvas on both forced palettes; on this branch none do.main. With forced colors on, no indicator paints as Canvas (0 of 132, against 132 of 132 onmain), nothing overflows horizontally, and I looked through the mobile screenshots for both palettes.main, and every stop shows a visible focus change in forced colors. The compiled CSS diff only adds forced-colors blocks and moves the inputoutline: none !importantundernot (forced-colors: active), so focus outside forced colors is unchanged.ariaSnapshot) of all 18 stories matchesmainin every mode and width (162 of 162). The change is CSS only.npm test(272 passed, including axe on every story), lint, format,check:api-snapshot,check:tokens,check:uswds,check:uswds-core.Docs: COMPONENTS.md now has the forced-colors step in the mask-icon recipe and in the manual checks. ARCHITECTURE.md mentions the forced-colors outline on text inputs.
Found but left out, probably worth separate issues:
.usa-input--error:focus-visiblekeeps the 1px red border and the outline is reset. That's 2.4.7 and it's the same onmain. This PR only changes it in forced colors, where the outline now paints..usa-alerticons vanish too. USWDS paints themblackthrough a mask, so the bug is upstream.GrayText. This fits with fix(form): preserve radio selection in forced colors #232.