Skip to content

fix: update hover text colors for Project Funding data viz#5915

Open
weimiao67 wants to merge 7 commits into
mainfrom
OPS-668/hover-text-color
Open

fix: update hover text colors for Project Funding data viz#5915
weimiao67 wants to merge 7 commits into
mainfrom
OPS-668/hover-text-color

Conversation

@weimiao67

@weimiao67 weimiao67 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What changed

Fixes hover-interaction color issues on the Project Funding tab and aligns the Project Funding by Portfolio viz with the All Portfolios page.

  • Project Funding by CAN (Previous FYs Carry-Forward): Changed the active hover percentage tag text from white to dark (text-ink) for readability against the cyan carry-forward background (#009ec1). (Tag.jsx)
  • Project Funding by Portfolio — segment colors now match PortfolioSummaryCards: buildPortfolioChartData previously assigned bar colors sequentially by position, so a given portfolio (e.g. HMRF) could get a different color depending on how many portfolios were present. It now assigns each portfolio its fixed color by abbreviation (resolving aliases like DDDO), identical to transformPortfoliosToChartData. A portfolio now always renders the same color across both views.
  • Shared hover text-color logic: Extracted getActivePortfolioTagTextColor / LIGHT_BACKGROUND_PORTFOLIOS into PortfolioSummaryCards.helpers.js. Both PortfolioLegend (All Portfolios) and ProjectFundingByPortfolioCard now use this single source of truth, so their hover effects (background + text color) stay identical and can't drift apart.
  • HMRF hover text is now white in both views. HMRF is excluded from LIGHT_BACKGROUND_PORTFOLIOS, so its active percentage tag shows white text on both the Project Funding by Portfolio viz and the All Portfolios page.

Note for reviewer: Because the text-color logic is now shared, the HMRF hover text on the All Portfolios page also changed from dark to white (it was previously dark there). This is intentional to keep the two views consistent.

Issue

#668 (comment)

How to test

  1. Navigate to a project detail page and open the Project Funding tab.
  2. Hover over the Project Funding by CAN bar — the Previous FYs Carry-Forward percentage tag should show dark text on the cyan background.
  3. Hover over each segment of the Project Funding by Portfolio bar — each percentage tag's background should match that portfolio's color on the All Portfolios page, and HMRF should show white text.
  4. Go to the All Portfolios page (/portfolios) and hover over the legend — verify the hover effect (background + text color) matches the Project Funding by Portfolio viz, including HMRF showing white text.

A11y impact

  • No accessibility-impacting changes in this PR

Storybook

  • N/A — change is page-specific or non-visual

Definition of Done Checklist

  • OESA: Code refactored for clarity
  • OESA: Dependency rules followed
  • Automated unit tests updated and passed
  • Automated integration tests updated and passed
  • Automated quality tests updated and passed
  • Automated load tests updated and passed
  • Automated a11y tests updated and passed
  • Automated security tests updated and passed
  • 90%+ Code coverage achieved
  • Form validations updated

@weimiao67 weimiao67 self-assigned this Jul 9, 2026
@weimiao67 weimiao67 marked this pull request as ready for review July 9, 2026 19:54

@josbell josbell left a comment

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.

Blocking: WCAG AA contrast failures on interactive hover elements

This PR's stated goal is fixing text colors, but it introduces two confirmed WCAG AA failures on the active hover state. Given this is a government application with Section 508 obligations, these need to be resolved before merge. Recommend looping in the design team — the color assignments for HMRF and OTIP may need to be revisited in Figma as well.


🔴 Required fixes

1. OTIP is miscategorized as a light background

--portfolio-bar-graph-otip: #1975aa is a medium-dark blue. Including it in LIGHT_BACKGROUND_PORTFOLIOS assigns dark text (#1B1B1B) to the hover tag, which yields a 3.42:1 contrast ratio — fails WCAG AA (minimum 4.5:1). White text would pass at 5.04:1.

Fix: remove "OTIP" from LIGHT_BACKGROUND_PORTFOLIOS.

2. HMRF hover text regresses to a WCAG AA failure

HMRF is intentionally excluded from LIGHT_BACKGROUND_PORTFOLIOS (gets white text on hover). --portfolio-bar-graph-hmrf: #428cae with white text yields 3.75:1 — fails WCAG AA. Dark text would pass at 4.59:1. The previous behavior (dark text) was actually more accessible.

Fix: add "HMRF" to LIGHT_BACKGROUND_PORTFOLIOS. This overrides the current "design intent" of white-on-HMRF — please flag this to the design team so Figma can be updated to match.


🟡 Should fix (touches code changed in this PR)

3. No active-state test coverage in ProjectFundingByPortfolioCard

The HorizontalStackedBar mock only destructures { data }setActiveId is never called, so isActive is always false in every test. The activeTextColor logic added by this PR (ProjectFundingByPortfolioCard.jsx line ~61) has zero test coverage. PortfolioLegend has equivalent active-state tests — this component should too.

4. fontWeight: "bold" vs fake-bold inconsistency in PortfolioLegend

The active percent <Tag> uses inline fontWeight: "bold", while the adjacent abbreviation and currency spans use the fake-bold CSS class (text-shadow, avoids layout shift). ProjectFundingByPortfolioCard uses fake-bold for the same element. Replace fontWeight: "bold" with fake-bold for consistency.


⚪ Optional

5. "DD" vs "DO" in LIGHT_BACKGROUND_PORTFOLIOS"DO" is the primary abbreviation, "DD" is the alias. The alias-aware lookup makes it work correctly, but using the primary abbreviation would be consistent with every other entry in the list.

@weimiao67

weimiao67 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@josbell Thanks for the thorough review — all five points were valid. I verified the two contrast failures by computing the WCAG ratios directly and confirmed the missing test coverage. All addressed:

🔴 Required fixes

  1. OTIP — removed from LIGHT_BACKGROUND_PORTFOLIOS, so it now renders white hover text (5.04:1 ✓, was 3.42:1 ✗). 2f5c5dcb
  2. HMRF — added to LIGHT_BACKGROUND_PORTFOLIOS, so it now renders dark hover text (4.59:1 ✓, was 3.75:1 ✗). Also updated the doc comment to record the WCAG rationale so the "design intent" isn't reintroduced. 2f5c5dcb
    • Flagging to design as you suggested — since OTIP and HMRF land on opposite sides of the 4.5:1 threshold, the fix ended up being "remove OTIP, add HMRF." Worth confirming in Figma.

🟡 Should fix

  1. Active-state coverage — the HorizontalStackedBar mock now destructures setActiveId and exposes a per-segment trigger, so isActive is actually exercised. Added tests covering the activeTextColor branch (both dark and light outcomes), the active-styling transition, and that only the activated segment is styled. 1fded90d / 8b223ac7
  2. fontWeight: "bold"fake-bold — the active percent <Tag> in PortfolioLegend now uses the fake-bold class, consistent with the adjacent spans and ProjectFundingByPortfolioCard. Avoids the layout shift from a real weight change. 8b223ac7

⚪ Optional

  1. "DD""DO" — switched to the primary abbreviation for consistency with the rest of the list. Alias-aware lookup means behavior is unchanged. 20dd22a1

All unit tests pass and lint/format are clean.

@weimiao67 weimiao67 requested a review from josbell July 10, 2026 16:37
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.

2 participants