fix(switch): resolve s1/express switch contrast accessibility#6097
Conversation
🦋 Changeset detectedLatest commit: c7136f4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 83 packages
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 |
7dad2fb to
7b24b4c
Compare
📚 Branch Preview Links🔍 First Generation Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
106c82f to
6ec4899
Compare
6565f7a to
db56e0b
Compare
db56e0b to
16775f7
Compare
1900f8b to
ea28842
Compare
ea28842 to
5fc9a27
Compare
| --system-switch-border-color-selected-default: var(--spectrum-gray-700); | ||
| --system-switch-border-color-selected-hover: var(--spectrum-gray-800); | ||
| --system-switch-border-color-selected-down: var(--spectrum-gray-900); | ||
| --system-switch-border-color-selected-focus: var(--spectrum-gray-800); |
There was a problem hiding this comment.
these correspond to the original's selected handle border color changes.
| --system-switch-border-color-default: var(--spectrum-gray-600); | ||
| --system-switch-border-color-hover: var(--spectrum-gray-700); | ||
| --system-switch-border-color-down: var(--spectrum-gray-800); | ||
| --system-switch-border-color-focus: var(--spectrum-gray-700); |
There was a problem hiding this comment.
these correspond to the original's unselected handle border color changes.
| --system-switch-handle-background-color-default: var(--spectrum-gray-600); | ||
| --system-switch-handle-background-color-hover: var(--spectrum-gray-700); | ||
| --system-switch-handle-background-color-down: var(--spectrum-gray-800); | ||
| --system-switch-handle-background-color-focus: var(--spectrum-gray-700); |
There was a problem hiding this comment.
these correspond to the original's unselected handle border color changes.
| --system-switch-border-color-down: var(--spectrum-gray-800); | ||
| --system-switch-border-color-focus: var(--spectrum-gray-700); | ||
| --system-switch-handle-border-color: var(--spectrum-gray-75); | ||
| --system-switch-handle-border-color-selected: var(--spectrum-gray-75); |
There was a problem hiding this comment.
The handle border color remains the same if a switch is checked or unchecked now.
| --system-switch-handle-background-color-default: var(--spectrum-gray-800); | ||
| --system-switch-handle-background-color-hover: var(--spectrum-gray-900); | ||
| --system-switch-handle-background-color-down: var(--spectrum-gray-900); | ||
| --system-switch-handle-background-color-focus: var(--spectrum-gray-900); |
There was a problem hiding this comment.
these correspond to the original's unselected handle border color changes.
| --system-switch-border-color-default: var(--spectrum-gray-800); | ||
| --system-switch-border-color-hover: var(--spectrum-gray-900); | ||
| --system-switch-border-color-down: var(--spectrum-gray-900); | ||
| --system-switch-border-color-focus: var(--spectrum-gray-900); |
There was a problem hiding this comment.
these correspond to the original's unselected handle border color changes.
| --system-switch-border-color-selected-default: var(--spectrum-gray-800); | ||
| --system-switch-border-color-selected-hover: var(--spectrum-gray-900); | ||
| --system-switch-border-color-selected-down: var(--spectrum-gray-900); | ||
| --system-switch-border-color-selected-focus: var(--spectrum-gray-900); |
There was a problem hiding this comment.
these correspond to the original's selected handle border color changes.
| --system-switch-border-color-down: var(--spectrum-neutral-content-color-down); | ||
| --system-switch-border-color-focus: var(--spectrum-neutral-content-color-key-focus); | ||
| --system-switch-handle-border-color: var(--spectrum-gray-25); | ||
| --system-switch-handle-border-color-selected: var(--spectrum-gray-25); |
There was a problem hiding this comment.
For all the themes now, the handle border color is always the same regardless of checked or unchecked.
caseyisonit
left a comment
There was a problem hiding this comment.
looks good to me and passes contrast ratio
| :host(:hover:active) #input + #switch::before, | ||
| :host([emphasized]:hover:active) #input + #switch::before { |
There was a problem hiding this comment.
Some of these styles were conflicting with the :hover media query, as well as conflicting with the cascade. The conflicting :hover styles have been removed and I fleshed out the read-only styles.
| :host(:hover) #input:not(:checked) + #switch { | ||
| border-color: Highlight; | ||
| box-shadow: inset 0 0 0 1px Highlight; | ||
| } |
There was a problem hiding this comment.
This comment is for the forced-colors query in general.
Most of these styles ended up being redundant once I correctly defined the --highcontrast variables. The high contrast variables were already in the styles, so there should be no need to manual be writing background color or border styles. If I missed something however, let me know and I can revert these changes.
Since this is also 1st-gen, I operated under the impression that maintaining the WHCM styles was more acceptable rather than removing them.
There was a problem hiding this comment.
There was a problem hiding this comment.
oh good catch! Looks like I didn't define the switch background color when disabled. Let me know if you see it still, but it should be fixed. d3f5186
| :host([disabled]) #input + #switch::before { | ||
| background-color: var(--highcontrast-switch-handle-background-color, var(--mod-switch-handle-background-color-disabled, var(--spectrum-switch-handle-background-color-disabled))); | ||
| border-color: var(--highcontrast-switch-handle-border-color-disabled, var(--mod-switch-handle-border-color-disabled, var(--spectrum-switch-handle-border-color-disabled))); | ||
| border-color: var(--highcontrast-switch-handle-border-color-disabled, var(--mod-switch-handle-border-color-default, var(--spectrum-switch-handle-border-color-disabled))); |
There was a problem hiding this comment.
TODO: this probably shouldn't change? double check since we redefined the handle-border-color-default to be the disabled color.
There was a problem hiding this comment.
uuuggh gh issues. double check since we redefine some of the custom props in the disabled selector.
| :host([checked]:hover) #input:enabled + #switch::before { | ||
| background-color: var(--highcontrast-switch-handle-background-color, var(--mod-switch-handle-background-color-selected-hover, var(--spectrum-switch-handle-background-color-selected))); | ||
| border-color: var(--highcontrast-switch-handle-border-color-selected-hover, var(--mod-switch-handle-border-color-selected-hover, var(--spectrum-switch-handle-border-color-selected))); | ||
| } | ||
|
|
||
| :host([checked]:hover:active) #input + #switch { | ||
| background-color: var(--highcontrast-switch-background-color-selected-down, var(--mod-switch-background-color-selected-down, var(--spectrum-switch-background-color-selected-down))); | ||
| border-color: var(--highcontrast-switch-border-color-selected-down, var(--mod-switch-border-color-selected-down, var(--spectrum-switch-border-color-selected-down))); |
There was a problem hiding this comment.
Some of these changes were conflicting with the CSS cascade, with hover overriding active or checked or both or combinations. Hopefully all states are still covered, but in particular, if y'all could double check combo states like active+hover, keyboard-focused+hover+checked, etc. that would be very helpful.
rise-erpelding
left a comment
There was a problem hiding this comment.
Looks great aside from the WHCM callout for the disabled switch that Steph called out! Nice work on this!
| transition: | ||
| background var(--mod-animation-duration-100, var(--spectrum-animation-duration-100)) ease-in-out, | ||
| border var(--mod-animation-duration-100, var(--spectrum-animation-duration-100)) ease-in-out, | ||
| box-shadow var(--mod-animation-duration-100, var(--spectrum-animation-duration-100)) ease-in-out; |
There was a problem hiding this comment.
This box-shadow transition had a very short life on main 😆
It looks SO much better now that we don't need it though!
|
|
||
| - **Changed**: Renamed `--highcontrast-switch-border-color` to `--highcontrast-switch-border-color-default` on `<sp-switch>`, and expanded it to full per-state tokens (`hover`, `focus`, `down`, `disabled`). Previously a single token controlled the track border color in all forced-colors states. | ||
|
|
||
| **If you were overriding `--highcontrast-switch-border-color` in Windows High Contrast styles, update your usage to the appropriate state-specific token.** |
To address some accessibility concerns regarding the contrast between switch's background color and light backgrounds, all themes have been updated. - condenses per-state handle border color tokens (default/hover/down/ focus) into --system-switch-handle-border-color and --system-switch-handle-border-color-selected tokens, since values are identical across all interaction states - remove the emphasized-selected-* tokens entirely because with the new styles they are the same as the non-emphasized variant - condenses --system-switch-handle-background-color-selected-* into a single token - adds --system-switch-border-color-* to each bridge matching the handle background color values per theme - updates S1 and Express unselected handle background colors to behave like the s2 foundations handle background where it responds to interaction states - renames --spectrum-switch-border-width-themed to --spectrum-switch-border-width since each theme now has a consistent border * fix(switch): remove unused variables in switch-overrides * fix(switch): clarify read-only state styles in switch.css * refactor(switch): incorporate new styles to all switch themes Due to accessibility contrast failures, all switches are updated to ensure the switch boundary is a high enough contrast ratio compared to its background. All switches now have a 2px border. - `--spectrum-switch-border-color-*` variables are defined via switch overrides now - replaces per-state handle border color references with the condensed `--spectrum-switch-handle-border-color`` and `--spectrum-switch-handle-border-color-selected`` tokens - replaces per-state selected handle background color references with the condensed `--spectrum-switch-handle-background-color-selected` token - removes the [emphasized][checked] handle border override block since emphasized and non-emphasized variants now share the same handle color - adds missing `--spectrum-switch-handle-border-color-selected-disabled` to the [disabled] block to have consistent disabled styling - adds `--highcontrast-switch-border-color-*` tokens to the forced-colors block so the track border responds correctly in Windows High Contrast - the --mod-switch-border-width-themed remains in tact so customization can still happen if consumers wish * fix(switch): whcm variables cleaned up - define the highcontrast variables correctly instead of manually changing properties, particularly for disabled switches - removes the manual property styles - correct a highcontrast variable name in switch.css - correct disabled handle border color * chore(switch): create changeset
d3f5186 to
0c8451b
Compare
* refactor(switch): condense system theme bridge tokens To address some accessibility concerns regarding the contrast between switch's background color and light backgrounds, all themes have been updated. - condenses per-state handle border color tokens (default/hover/down/ focus) into --system-switch-handle-border-color and --system-switch-handle-border-color-selected tokens, since values are identical across all interaction states - remove the emphasized-selected-* tokens entirely because with the new styles they are the same as the non-emphasized variant - condenses --system-switch-handle-background-color-selected-* into a single token - adds --system-switch-border-color-* to each bridge matching the handle background color values per theme - updates S1 and Express unselected handle background colors to behave like the s2 foundations handle background where it responds to interaction states - renames --spectrum-switch-border-width-themed to --spectrum-switch-border-width since each theme now has a consistent border * fix(switch): remove unused variables in switch-overrides * fix(switch): clarify read-only state styles in switch.css * refactor(switch): incorporate new styles to all switch themes Due to accessibility contrast failures, all switches are updated to ensure the switch boundary is a high enough contrast ratio compared to its background. All switches now have a 2px border. - `--spectrum-switch-border-color-*` variables are defined via switch overrides now - replaces per-state handle border color references with the condensed `--spectrum-switch-handle-border-color`` and `--spectrum-switch-handle-border-color-selected`` tokens - replaces per-state selected handle background color references with the condensed `--spectrum-switch-handle-background-color-selected` token - removes the [emphasized][checked] handle border override block since emphasized and non-emphasized variants now share the same handle color - adds missing `--spectrum-switch-handle-border-color-selected-disabled` to the [disabled] block to have consistent disabled styling - adds `--highcontrast-switch-border-color-*` tokens to the forced-colors block so the track border responds correctly in Windows High Contrast - the --mod-switch-border-width-themed remains in tact so customization can still happen if consumers wish * fix(switch): whcm variables cleaned up - define the highcontrast variables correctly instead of manually changing properties, particularly for disabled switches - removes the manual property styles - correct a highcontrast variable name in switch.css - correct disabled handle border color * chore(switch): create changeset * chore: update golden image hash

Description
This PR addresses two related switch accessibility concerns in S1/Express themes:
--spectrum-switch-border-width-themedto--spectrum-switch-border-width:The
-themedsuffix is no longer needed as all themes will now have a border; the token now maps consistently to--spectrum-border-width-200(2px) across both S1 and Express instead of 0px. This removes the 0px override which contributed to low contrast for the switch boundary in S1/Express. The--mod-switch-border-width-themedintroduced in feat(switch): token mapping updates for s2-foundations #6065 remains in tact.In both S1 and Express
system-theme-bridge.css, selected handle border color tokens resolve to--spectrum-gray-75to maintain the 1st-gen styles against the filled (checked) track background.The switch.css file was incorrectly overriding some hover styles and active styles, while the code comments only referred to read-only styles. switch.css now only contains read-only overrides, and parts of the
:hovermedia query were also overriding active styling, all of which should be fixed now.If properly redefined, all of the manual styling in the forced-colors query should be redundant.
--highcontrast-switch-border-colorwas expanded to include per-state tokens, so that those manual selector blocks were unnecessary.Motivation and context
The switch component in S1 and Express themes had no visible edge against certain backgrounds, failing the required 3:1 contrast ratio (WCAG 2.1 SC 1.4.11 Non-text Contrast). This PR introduces a border that meets the contrast, but introduces a drastic visual difference for legacy theming.
Related issue(s)
Screenshots (if appropriate)
Before (contrast failures in Express and S1) 🚫
Express/S1/S2
After (contrast met in all themes) ✅
Express/S1/S2
Author's checklist
Reviewer's checklist
patch,minor, ormajorfeaturesManual review test cases
Design discussion and approval
Custom property rename: --spectrum-switch-border-width-themed is now --spectrum-switch-border-width
--mod-switch-border-width-themedto something new, like 1px or 20px, and verify that you see the right changes in the browserHandle border on checked state (Express & S1)
Active+checked border color
#switchelement should match colors/behaviors.i. S1 and Express themes have a separate active/down style (with an additional token color stop) in the emphasized variant, unlike S2 foundations.
Read-only switches
WHCM styles
box-shadowstyles were removed. Previously, box-shadow was being used to add a border to WHCM (when S1 and Express were borderless). Now that they have a border,box-shadowis unnecessary. 🥳Device review
Accessibility testing checklist
Required: Complete each applicable item and document your testing steps (replace the placeholders with your component-specific instructions).
Keyboard
What to test for:
Focus order is logical; Tab reaches the component and all interactive descendants; Enter/Space activate where appropriate; arrow keys work for tabs, menus, sliders, etc.; no focus traps; Escape dismisses when applicable; focus indicator is visible.
Screen reader
What to test for:
Role and name are announced correctly; state changes (e.g. expanded, selected) are announced; labels and relationships are clear; no unnecessary or duplicate announcements.