Update light-high-contrast fgColor tokens to custom hex values between scale levels 5 and 6#1346
Conversation
🦋 Changeset detectedLatest commit: bc084ef The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Agent-Logs-Url: https://github.com/primer/primitives/sessions/cfd10d4a-6ef1-4a41-b809-58e214034831 Co-authored-by: janmaarten-a11y <83665577+janmaarten-a11y@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adjusts light-high-contrast semantic foreground status colors to improve chromatic distinction between statuses (e.g., open/closed/done) while keeping high-contrast compliance.
Changes:
- Updated seven
fgColor.*token overrides forlight-high-contrastfrom base scale level6to5. - Added a changeset to publish the token update as a patch release.
Show a summary per file
| File | Description |
|---|---|
src/tokens/functional/color/fgColor.json5 |
Moves light-high-contrast overrides for the seven semantic fgColor tokens from *.6 → *.5. |
.changeset/fgcolor-light-high-contrast-level-5.md |
Declares a patch changeset describing the token adjustments and links the related issue. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 0
Design Token Diff (CSS)
|
Design Token Diff (StyleLint)
|
Design Token Diff (Figma)
|
|
@copilot I'm getting a failing contrast check, as we tested the 7:1 contrast radio successfully on bgColor.default, but not bgColor.muted. How should we resolve this?
|
… in light-high-contrast Agent-Logs-Url: https://github.com/primer/primitives/sessions/04c22cdb-0f77-450f-84d2-cfe42dc64578 Co-authored-by: janmaarten-a11y <83665577+janmaarten-a11y@users.noreply.github.com>
The failures were caused by the level 5 fgColors (less dark, more saturated) no longer meeting 7:1 against the light-high-contrast backgrounds that had been tuned for the darker level 6 values. Fixed in f2cc524 by lightening two background tokens in
Both changes only make backgrounds lighter, so no existing passing pairs can regress. All 12 previously failing pairs now pass at 7:1+ (ranging from 7.14:1 to 7.21:1). |
|
@copilot The 12 failures are all foreground colors narrowly missing the 7:1 high-contrast threshold against The issue is that level 5 (this PR) is too light for 7:1, but level 6 (the original) was too dark to tell the status colors apart. We can't just change There's precedent for this situation. When @langermank built the dark high-contrast themes in #1190, several fgColor overrides were set to hand-picked hex values between scale steps because no single step satisfied both contrast and visual quality. For example,
Let's follow the same approach here: pick custom hex values between level 5 and level 6 for each color in
For reference, the HSL lightness targets are roughly 55-60% of the way from level 5 toward level 6 for each color. Here are the level 5 and level 6 bounds to interpolate between:
The two |
Done in b24544d. Reverted the background token changes and instead applied custom hex values for each For red (
|
|
@copilot Thanks for that. This has become a more complex problem than originally thought. Each custom hex override is a deviation from the scale system that needs to be individually justified and maintained. There's a meaningful difference between three targeted overrides for a specific accessibility issue and seven overrides that "round out" the change. The extra four add maintenance cost without a clear user-facing problem driving them. Reverting |
|
@janmaarten-a11y I've opened a new pull request, #1347, to work on those changes. Once the pull request is ready, I'll request review from you. |
…success, danger, and done (#1347) * Initial plan * Revert accent, attention, severe, sponsors to base.color.*.6 in light-high-contrast Agent-Logs-Url: https://github.com/primer/primitives/sessions/233af47e-2c0a-4412-8864-f9fbc12605b7 Co-authored-by: janmaarten-a11y <83665577+janmaarten-a11y@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: janmaarten-a11y <83665577+janmaarten-a11y@users.noreply.github.com>
|
@janmaarten-a11y can we avoid custom hex colors and use an even stronger contrast in the scale? I'd like to avoid adding complexity through custom colors. |
|
@lukasoppermann I didn't want to use custom hex values here, but I didn't see another option. Currently, we're using I tried bumping it to That's where I found @langermank had run into the same issue with Dark High Contrast and ended up using custom hex values on a few colors for the same reason. If we really want to avoid that, we have a few options:
I tried the first one, but worried that it would have a lot of other downstream effects throughout the site and generally make it more difficult to differentiate default and muted backgrounds when using Light High Contrast. What do you think? |
|
@janmaarten-a11y okay, now I get it. Makes sense. I guess, less use hex for now. Since this is json5, can you try adding a comment to the colors with a short mention why they use custom colors for later? |
Improves visual differentiation between status colors (open/closed/done) in the light high-contrast theme by updating fgColor tokens to custom hex values between scale levels 5 and 6.
Summary
In the
light-high-contrasttheme, the three PR/issue status foreground color tokens (fgColor.success,fgColor.danger,fgColor.done) resolved to base color scale level 6. At this level, the colors are so dark that they lose chromatic distinction and become hard to tell apart. This is most visible on PR/issue list pages, where the open (green), closed (red), and done/merged (purple) status icons appear side by side.No single scale step satisfies both requirements: level 5 is too light to clear the 7:1 high-contrast minimum against
bgColor-muted(#e6eaef), while level 6 is too dark to preserve chromatic distinction between status colors. Following the precedent established by @langermank on the dark high-contrast themes (e.g.fgColor.accentin dark HC uses#74B9FF, between blue.2 and blue.3), custom hex values interpolated between scale levels 5 and 6 are used instead. These are as close to level 5 as possible (preserving saturation) while clearing 7:1 against all required background pairings.How we got here
The initial approach was to move all seven
light-high-contrastfgColor overrides from{base.color.*.6}to{base.color.*.5}. Contrast validation revealed that level 5 narrowly fails 7:1 againstbgColor-muted, landing between 6.43:1 and 6.70:1 for all seven colors. Rather than changing background tokens (which are used broadly across the UI), we followed the dark HC precedent of hand-picking hex values between scale steps. With that shift, the scope was also narrowed to the three tokens that directly address the reported issue (success,danger,done), reverting the other four (accent,attention,severe,sponsors) to their original level-6 references. If those turn out to need the same treatment later, that can be a separate PR with its own justification.List of notable changes
In
src/tokens/functional/color/fgColor.json5, updated thelight-high-contrastoverride for three status tokens from base color scale level 6 references to custom hex values between levels 5 and 6:bgColor-muted(#e6eaef)fgColor.success{base.color.green.6}(#024c1a)#04591ffgColor.danger{base.color.red.6}(#86061d)#960d1efgColor.done{base.color.purple.6}(#512598)#5e2bb4The
fgColor.dangervalue also clears 7.03:1 againstbutton-danger-bgColor-rest(#e0e6eb), resolving thebutton-danger-fgColor-restandbutton-danger-iconColor-restcontrast failures that were encountered when we attempted to switch to{base.color.red.5}.The following tokens are not directly edited but inherit from the changed tokens:
fgColor.openinherits fromfgColor.successfgColor.closedinherits fromfgColor.dangerfgColor.upsellinherits fromfgColor.doneNo background tokens were changed. No other themes, base scales, or token categories are affected. The remaining four
light-high-contrastfgColor tokens (accent,attention,severe,sponsors) stay at their existing{base.color.*.6}values.What should reviewers focus on?
light-high-contrastoverrides forsuccess,danger, anddonechanged infgColor.json5. No other theme, base scale, or background token values should differSteps to test
light-high-contrasttheme on a repo with a mix of open, closed, and merged PRsfgColor-open(green),fgColor-closed(red), andfgColor-done(purple) status icons are visually distinct from one anothernpm run validate:contrastto confirm all contrast pairs pass at 7:1+Supporting resources
Contributor checklist
Reviewer checklist