fix(a11y): bring the reported colour-contrast failures up to AA - #356
Merged
Merged
Conversation
|
📦 Preview published for commit Install the preview with dist-tag: npm install @vc-shell/framework@pr-356Or pin to the exact commit: npm install @vc-shell/framework@2.6.0-rc.0-pr356.38334f4Published packages (dist-tag
|
maksimzinchuk
force-pushed
the
fix/VCST-5862-contrast
branch
from
September 4, 2026 12:10
4dee172 to
a0f6fe4
Compare
Measured with axe on the running Vendor Portal rather than derived from the source: the violations come from a few elements, repeated, not from 25 independent places. - User role label: 2.41:1 light, 3.41:1 dark. -400 is the palette's muted/disabled ink; -500 is the one it documents as secondary text. - Relative timestamps: 2.52:1 on a white row and 2.09:1 on the selected-row tint; 3.16:1 and 2.83:1 in dark. -600 rather than -500, because -500 is still 3.94:1 on that tint. - Sorted column header: 4.41:1, just under. -800 is the next step on the same scale. Those three are token references, not values, so each theme resolves them against its own scale and one change fixes both: light clears at 4.54 / 7.81 / 5.6, dark at 5.09 / 5.76 / 8.96. The environment banner needed more than a swap. Its label was white on every variant, measuring 1.70:1 to 3.32:1 in light, and in dark the theme-following ink already failed on primary and danger. Sweeping all seven variants in both themes shows black is the only ink that clears AA on every accent background (4.56:1 at worst, dark danger, up to 12.33:1), and no palette token can carry it: every candidate flips with the theme while these backgrounds stay mid-tone. So the six coloured variants take a fixed black, and the neutral variant — with the unmodified banner, which shares its background — keeps the theme-following token, which passes there and where black would not. No background changed. -400 stays wherever it marks a disabled or inactive control, which WCAG 1.4.3 exempts.
maksimzinchuk
force-pushed
the
fix/VCST-5862-contrast
branch
from
September 4, 2026 12:38
a0f6fe4 to
38334f4
Compare
maksimzinchuk
added a commit
that referenced
this pull request
Sep 8, 2026
…358) QA found `.dashboard-stat-item__value--success` at **4.13:1** on vcmp-dev while verifying VCST-5862, and correctly noted neither #356 nor #154 touches it. Checking the other two modifiers found the same defect: | modifier | light before | dark before | after | after (dark) | | --- | --- | --- | --- | --- | | success | **4.13** | 7.54 | `-700` → 6.88 | 9.45 | | warning | **2.01** | 7.46 | `-800` → 6.22 | 10.60 | | danger | **3.80** | **4.33** | `-700` → 6.01 | 5.76 | ### Why the shades differ Each is the **lightest step that clears AA in both themes**, measured rather than picked for uniformity. `-700` leaves warning at 3.98 in light, so amber takes a deeper step — that is a property of amber, not an inconsistency, and the comment in the file says so with the numbers. ### Why only one of the three was reported The modifier renders only when a widget carries a stat of that kind, so whether it appears depends on the data in front of you. That is also why my own "after: 0" run on VCST-5862 did not show even the success case — the widgets held no success stat at that moment. QA made the same point about node counts being row-count dependent; the distinct **signature** is the stable unit, not the node total. Measured from the live cascade by forcing each modifier, rather than waiting for data to produce them. ### Verification `vue-tsc` clean · `vitest run` 4158 passed, exit 0 · `lint:check`, prettier and stylelint clean. Browser sweep of all three modifiers in both themes, all six combinations clearing AA. Committed with `--no-verify`: the pre-commit hook lints only the staged files, and that narrow invocation reports a false `import/no-unresolved` the full `lint:check` does not. Contributes to VCST-5862
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 the 25 violations actually are
Measured with axe on the running Vendor Portal rather than derived from the source. They come from a few elements, repeated — not 25 independent places. That matters, because
--neutrals-400has 46 uses in the framework and a blanket swap would have been wrong.--neutrals-500--neutrals-600--primary-800--neutrals-600rather than-500for the timestamps because-500is still 3.94:1 on the selected-row tint.The palette's own comments already say what these tokens are for:
-400is "muted text / disabled",-500is "secondary text (WCAG AA ~5:1)". The defect was text reaching for the disabled ink.Both themes, from one change
The first three are token references, not values, so each theme resolves them against its own scale. The ticket audited Light only; Dark had the same two defects and is fixed by the same swap.
The environment banner needed more than a swap
Its label was white on every variant — 1.70:1 to 3.32:1 in Light, worst on amber, and no shade of amber fixes white text. In Dark the theme-following ink already failed on
primary(4.34) anddanger(3.15) before any change here.Sweeping all seven variants in both themes, from the live cascade:
--additional-50(dark's value)--neutrals-800Black is the only ink that clears AA on every accent background, and no palette token can carry it: every candidate flips with the theme —
--additional-950is#000000in Light but#ebebebin Dark — while these backgrounds stay mid-tone in both. Hence a fixed value, with the reasoning in the comment.The
neutralvariant, and an unmodified banner which shares its background, keep the theme-following token: that grey is too dark for black (4.43) and the token passes in both (4.74 / 4.72).No background changed — every variant keeps the colour it was designed with; only the label moved.
Not swapped
--neutrals-400stays wherever it marks a disabled or inactive control — WCAG 1.4.3 exempts those, and darkening them would make disabled read as enabled.The toolbar's disabled title was in QA's list and is not fixed here: axe flagged it only because the button exposed no disabled state at all, so axe could not know the exemption applied. #355 adds
aria-disabledand the finding disappears — confirmed by elimination, since this PR does not touch that colour.Verification
Full axe pass over
#/,#/products,#/ordersand#/offers, both themes:The last three failures were app code, not framework — the dashboard widget empty states — fixed in vendor-portal#154. With that and this in, the four routes report zero axe violations of any rule in either theme.
vue-tscclean ·vitest run4123 passed, exit 0 ·lint:check, prettier and stylelint clean.One limit worth stating: the story-level axe gate has
color-contrastdisabled as a documented exception, so nothing in CI keeps this from drifting back.Committed with
--no-verify: the pre-commit hook lints only the staged files, and that narrow invocation reports a falseimport/no-unresolvedthe fulllint:checkdoes not.Closes VCST-5862