fix(AvatarStatusDot): resolve WCAG 2.1 SC 1.4.1 use-of-color failure#4218
fix(AvatarStatusDot): resolve WCAG 2.1 SC 1.4.1 use-of-color failure#4218gonzoblasco wants to merge 1 commit into
Conversation
The AvatarStatusDot component relied on colour alone to convey status (success=green, neutral=gray, error=red), which fails WCAG 2.1 Success Criterion 1.4.1 (Use of Color). Changes: - Add default icons per variant (checkmark, dash, cross) so shape reinforces meaning alongside colour at medium+ avatar sizes - Add default accessible labels per variant so screen readers always announce status meaning, including at the smallest avatar tier where icons cannot be rendered - Make fall back to a sensible default per variant - Allow to explicitly suppress the default icon - Update JSDoc with WCAG 1.4.1 rationale Backward compatible: explicit and props still take precedence. Consumers who already pass these props see no change. Closes facebook#4143
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
humbertovirtudes
left a comment
There was a problem hiding this comment.
Thanks for digging into the 1.4.1 use-of-color failure on the status dot, this is a real gap and the instinct to add both a default per-variant label and a non-color mark is the right one.
The blocker is not the code, it is that this collides with #4157, which solves the same WCAG 1.4.1 issue on the same component a different way. The two cannot both land, so we need to converge on one approach before either moves.
Having read both, I think #4157 is the stronger base to build on: it pairs each variant with a distinct built-in shape (filled dot / ring / minus bar) drawn as a stroked SVG, which stays legible at the smallest avatar sizes where an icon cannot render at all. This PR's default-icon path only differentiates at medium and larger sizes.
Where this PR is clearly additive and worth carrying over into that effort:
- The default per-variant accessible label (so an unlabeled dot is not silent) is valuable. Worth noting #4157 documents that a label on the dot is currently not announced inside Avatar because the Avatar root is
role="img", which prunes descendant semantics, so let us make sure the label actually reaches AT as part of whichever approach wins. - If we keep default labels, "Online" / "Busy" / "Away" read better than "Success" / "Neutral" / "Error" for a presence dot.
Could you sync with @AKnassa on #4157 and fold the label piece in there? Genuinely good problem to have two solutions; let us land the best combined one.
|
Closing in favour of #4157, which solves the same WCAG 1.4.1 issue with SVG shapes that work at every avatar size — a stronger approach than the icon-based one here. The default accessible label per variant piece from this PR is being carried over into #4157 (with presence-oriented naming: "Online"/"Away"/"Busy" per @humbertovirtudes's suggestion). Thanks for the review and the clear direction — the combined result will be better than either PR alone. |
|
Closing per maintainer feedback — converging with #4157. |
Summary
Resolves #4143
The
AvatarStatusDotcomponent relied on colour alone to convey status meaning (green=success, gray=neutral, red=error), which fails WCAG 2.1 Success Criterion 1.4.1 (Use of Color).Users with colour vision deficiencies (deuteranopia, protanopia, tritanopia, achromatopsia) cannot distinguish between the three status states, and screen readers have no way to announce the status when no
labelis provided.Solution
Two-pronged approach to ensure status is never conveyed by colour alone:
1. Default icons per variant (shape differentiation)
When no
iconprop is provided, a default SVG icon is rendered inside the dot based on the variant:successneutralerrorThese icons are rendered at medium+ avatar sizes (≥ 40px) where there is enough room. At the smallest tier (≤ 36px, dotSize=10px), icons are not legible, so shape differentiation falls back to the accessible label.
2. Default accessible labels per variant (screen reader support)
When no
labelprop is provided, a default label is derived from the variant ("Success","Neutral","Error"). This ensures:role="img"attribute is always set when there's a labelBackward compatibility
labelprop still takes precedence over the defaulticonprop still takes precedence over the defaulticon={null}explicitly suppresses the default iconWhat this fixes
Before (WCAG 1.4.1 fail):
After (WCAG 1.4.1 pass):
Testing
Added 8 test cases covering:
icon={null}suppressionChecklist