Skip to content

fix(switch): resolve s1/express switch contrast accessibility#6097

Merged
marissahuysentruyt merged 2 commits intomainfrom
marissahuysentruyt/swc-1115-switch-contrast-a11y
Mar 26, 2026
Merged

fix(switch): resolve s1/express switch contrast accessibility#6097
marissahuysentruyt merged 2 commits intomainfrom
marissahuysentruyt/swc-1115-switch-contrast-a11y

Conversation

@marissahuysentruyt
Copy link
Copy Markdown
Collaborator

@marissahuysentruyt marissahuysentruyt commented Mar 19, 2026

Description

This PR addresses two related switch accessibility concerns in S1/Express themes:

  1. Renamed --spectrum-switch-border-width-themed to --spectrum-switch-border-width:
    The -themed suffix 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-themed introduced in feat(switch): token mapping updates for s2-foundations #6065 remains in tact.
  2. Fixed handle border colors for selected states:
    In both S1 and Express system-theme-bridge.css, selected handle border color tokens resolve to --spectrum-gray-75 to maintain the 1st-gen styles against the filled (checked) track background.
  3. Fixed cascade
    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 :hover media query were also overriding active styling, all of which should be fixed now.
  4. Fixed WHCM query:
    If properly redefined, all of the manual styling in the forced-colors query should be redundant. --highcontrast-switch-border-color was 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)

  • fixes SWC-1115

Screenshots (if appropriate)

Before (contrast failures in Express and S1) 🚫

Express/S1/S2

Screenshot 2026-03-10 at 8 18 15 AM Screenshot 2026-03-10 at 8 18 05 AM Screenshot 2026-03-10 at 8 16 18 AM

After (contrast met in all themes) ✅

Express/S1/S2

Screenshot 2026-03-23 at 12 58 22 PM Screenshot 2026-03-23 at 12 58 12 PM Screenshot 2026-03-23 at 12 59 48 PM

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it.

Reviewer's checklist

  • Includes a Github Issue with appropriate flag or Jira ticket number without a link
  • Includes thoughtfully written changeset if changes suggested include patch, minor, or major features
  • Automated tests cover all use cases and follow best practices for writing
  • Validated on all supported browsers
  • All VRTs are approved before the author can update Golden Hash

Manual review test cases

  • Design discussion and approval

  • Custom property rename: --spectrum-switch-border-width-themed is now --spectrum-switch-border-width

    1. Open the switch documentation page in S1 and Express themes
    2. Inspect the switch track border to confirm it renders at 2px (not 0px)
    3. Confirm no regressions in track sizing or handle positioning (handle translate calculations (added in feat(switch): token mapping updates for s2-foundations #6065) depend on this 2px value).
    4. Set --mod-switch-border-width-themed to something new, like 1px or 20px, and verify that you see the right changes in the browser
    5. No layout shifts are expected, but S1 and Express should have VRT diffs regarding the border.
    6. No expected VRTs should be returned for S2 foundations.
  • Handle border on checked state (Express & S1)

    1. Open the switch docs page in S1 Storybook light and dark modes
    2. Toggle a switch to checked to confirm the handle border is --spectrum-gray-75 against the gray-700 filled track
    3. Hover, click, and keyboard focus the checked switch and verify the handle/thumb border color remains --spectrum-gray-75. The track should respond accordingly: hover bg is gray-800; focus bg is gray-800, active/down bg is gray-900
    4. Open the switch Storybook page in the Express theme
    5. Repeat the above steps, with the same expected behavior: --spectrum-gray-75 should be the border color for the switch handle when the switch is selected/checked, regardless of interaction. Hover/focus/active bg is gray-900
    6. Confirm the emphasized switch behaves in the same way for both S1 and Express.
  • Active+checked border color

    1. Click and hold a checked switch in S1 and Express themes
    2. Confirm the border-color transitions to --spectrum-switch-border-color-selected-down. The background and border of the #switch element 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

    1. Visit the Read only Storybook for any theme switch
    2. Verify the styles remain static no matter the interactive state. All styles were moved into the switch.css file to make sure they override other query styles appropriately.
  • WHCM styles

    1. Enable forced-colors (e.g. Windows High Contrast) using devtools to simulate or use AssistivLabs.
    2. Verify any box-shadow styles 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-shadow is unnecessary. 🥳
    3. Verify disabled states are consistent: there shouldn't be any weird colors, no state changes, etc.
    4. For enabled/non-disabled switches, make sure the states are consistent: hover/focus/active should all just be the same style. Checked and Emphasized Checked switched are identical as well.

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

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.

    1. Go to Switch story in 1st-gen Storybook.
    2. Tab to switch, activate with Space, toggle checked state.
    3. Expect focus ring visible and switch toggles correctly.
  • 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.

    1. Go to Switch story in 1st-gen Storybook.
    2. Focus switch and activate; listen for “switch” role and "on”/"off" state. ("on, Switch, switch")
    3. Expect the state, then label (slot or aria-label) announced, then role to be announced. ("on, Switch label, switch")

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 19, 2026

🦋 Changeset detected

Latest commit: c7136f4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 83 packages
Name Type
@spectrum-web-components/switch Minor
@spectrum-web-components/styles Minor
@spectrum-web-components/story-decorator Minor
@spectrum-web-components/bundle Minor
@spectrum-web-components/card Minor
@spectrum-web-components/illustrated-message Minor
@spectrum-web-components/custom-vars-viewer Minor
@spectrum-web-components/vrt-compare Minor
@spectrum-web-components/theme Minor
@spectrum-web-components/truncated Minor
documentation Patch
@spectrum-web-components/overlay Minor
@spectrum-web-components/slider Minor
@spectrum-web-components/action-menu Minor
@spectrum-web-components/combobox Minor
@spectrum-web-components/contextual-help Minor
@spectrum-web-components/menu Minor
@spectrum-web-components/picker Minor
@spectrum-web-components/popover Minor
@spectrum-web-components/tooltip Minor
@spectrum-web-components/breadcrumbs Minor
@spectrum-web-components/action-bar Minor
@spectrum-web-components/coachmark Minor
@spectrum-web-components/accordion Minor
@spectrum-web-components/action-button Minor
@spectrum-web-components/action-group Minor
@spectrum-web-components/alert-banner Minor
@spectrum-web-components/alert-dialog Minor
@spectrum-web-components/asset Minor
@spectrum-web-components/avatar Minor
@spectrum-web-components/badge Minor
@spectrum-web-components/button-group Minor
@spectrum-web-components/button Minor
@spectrum-web-components/checkbox Minor
@spectrum-web-components/clear-button Minor
@spectrum-web-components/close-button Minor
@spectrum-web-components/color-area Minor
@spectrum-web-components/color-field Minor
@spectrum-web-components/color-handle Minor
@spectrum-web-components/color-loupe Minor
@spectrum-web-components/color-slider Minor
@spectrum-web-components/color-wheel Minor
@spectrum-web-components/dialog Minor
@spectrum-web-components/divider Minor
@spectrum-web-components/dropzone Minor
@spectrum-web-components/field-group Minor
@spectrum-web-components/field-label Minor
@spectrum-web-components/help-text Minor
@spectrum-web-components/icon Minor
@spectrum-web-components/icons-ui Minor
@spectrum-web-components/icons-workflow Minor
@spectrum-web-components/icons Minor
@spectrum-web-components/iconset Minor
@spectrum-web-components/infield-button Minor
@spectrum-web-components/link Minor
@spectrum-web-components/meter Minor
@spectrum-web-components/modal Minor
@spectrum-web-components/number-field Minor
@spectrum-web-components/picker-button Minor
@spectrum-web-components/progress-bar Minor
@spectrum-web-components/progress-circle Minor
@spectrum-web-components/radio Minor
@spectrum-web-components/search Minor
@spectrum-web-components/sidenav Minor
@spectrum-web-components/split-view Minor
@spectrum-web-components/status-light Minor
@spectrum-web-components/swatch Minor
@spectrum-web-components/table Minor
@spectrum-web-components/tabs Minor
@spectrum-web-components/tags Minor
@spectrum-web-components/textfield Minor
@spectrum-web-components/thumbnail Minor
@spectrum-web-components/toast Minor
@spectrum-web-components/top-nav Minor
@spectrum-web-components/tray Minor
@spectrum-web-components/underlay Minor
@spectrum-web-components/base Minor
@spectrum-web-components/grid Minor
@spectrum-web-components/opacity-checkerboard Minor
@spectrum-web-components/reactive-controllers Minor
@spectrum-web-components/shared Minor
@spectrum-web-components/eslint-plugin Minor
@spectrum-web-components/stylelint-header-plugin Minor

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

@marissahuysentruyt marissahuysentruyt self-assigned this Mar 19, 2026
@marissahuysentruyt marissahuysentruyt added 1.0.0 Issues that should be addressed for a 1.0 release! Component:Switch a11y Issues or PRs related to accessibility Status:WIP PR is a work in progress or draft labels Mar 19, 2026
@marissahuysentruyt marissahuysentruyt changed the title Marissahuysentruyt/swc 1115 switch contrast a11y fix(switch): resolve s1/express switch contrast accessibility Mar 19, 2026
@marissahuysentruyt marissahuysentruyt changed the base branch from main to marissahuysentruyt/swc-1070-switch-token-mapping March 19, 2026 18:27
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1115-switch-contrast-a11y branch from 7dad2fb to 7b24b4c Compare March 19, 2026 18:28
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 19, 2026

📚 Branch Preview Links

🔍 First Generation Visual Regression Test Results

When 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: pr-6097

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1115-switch-contrast-a11y branch from 106c82f to 6ec4899 Compare March 20, 2026 20:10
@marissahuysentruyt marissahuysentruyt marked this pull request as ready for review March 23, 2026 18:25
@marissahuysentruyt marissahuysentruyt requested a review from a team as a code owner March 23, 2026 18:25
@marissahuysentruyt marissahuysentruyt added do-not-merge NO MERGE-Y! Status:Ready for review PR ready for review or re-review. and removed Status:WIP PR is a work in progress or draft labels Mar 23, 2026
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1070-switch-token-mapping branch from 6565f7a to db56e0b Compare March 23, 2026 18:57
@marissahuysentruyt marissahuysentruyt added Status:WIP PR is a work in progress or draft and removed Status:Ready for review PR ready for review or re-review. labels Mar 23, 2026
@marissahuysentruyt marissahuysentruyt marked this pull request as draft March 23, 2026 19:08
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1070-switch-token-mapping branch from db56e0b to 16775f7 Compare March 24, 2026 16:39
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1115-switch-contrast-a11y branch from 1900f8b to ea28842 Compare March 24, 2026 16:47
Comment thread 1st-gen/packages/switch/src/spectrum-switch.css Outdated
Base automatically changed from marissahuysentruyt/swc-1070-switch-token-mapping to main March 24, 2026 18:56
@marissahuysentruyt marissahuysentruyt added Status:Ready for review PR ready for review or re-review. and removed Status:WIP PR is a work in progress or draft do-not-merge NO MERGE-Y! labels Mar 24, 2026
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1115-switch-contrast-a11y branch from ea28842 to 5fc9a27 Compare March 24, 2026 19:14
@marissahuysentruyt marissahuysentruyt marked this pull request as ready for review March 24, 2026 19:31
Comment on lines +581 to +584
--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);
Copy link
Copy Markdown
Collaborator Author

@marissahuysentruyt marissahuysentruyt Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these correspond to the original's selected handle border color changes.

Comment on lines +585 to +588
--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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these correspond to the original's unselected handle border color changes.

Comment on lines +598 to +601
--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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handle border color remains the same if a switch is checked or unchecked now.

Comment on lines +598 to +601
--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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these correspond to the original's unselected handle border color changes.

Comment on lines +585 to +588
--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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these correspond to the original's unselected handle border color changes.

Comment on lines +581 to +584
--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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all the themes now, the handle border color is always the same regardless of checked or unchecked.

Copy link
Copy Markdown
Contributor

@caseyisonit caseyisonit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me and passes contrast ratio

Comment on lines -22 to -23
:host(:hover:active) #input + #switch::before,
:host([emphasized]:hover:active) #input + #switch::before {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines -410 to -413
:host(:hover) #input:not(:checked) + #switch {
border-color: Highlight;
box-shadow: inset 0 0 0 1px Highlight;
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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.

I do see one issue that is a change from current which is this "white" background on #switch for a dark theme (screenshot is S1)
image

That background doesn't show for current prod, and not having it (or keeping the current override perhaps) seems to adapt better for contrast:
image

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Screenshot 2026-03-25 at 12 00 56 PM

: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)));
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: this probably shouldn't change? double check since we redefined the handle-border-color-default to be the disabled color.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uuuggh gh issues. double check since we redefine some of the custom props in the disabled selector.

Comment on lines +315 to +322
: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)));
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

@rise-erpelding rise-erpelding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.**
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great!

Copy link
Copy Markdown
Contributor

@5t3ph 5t3ph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! :shipit:

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
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1115-switch-contrast-a11y branch from d3f5186 to 0c8451b Compare March 25, 2026 20:18
@marissahuysentruyt marissahuysentruyt merged commit f842573 into main Mar 26, 2026
28 checks passed
@marissahuysentruyt marissahuysentruyt deleted the marissahuysentruyt/swc-1115-switch-contrast-a11y branch March 26, 2026 12:33
rubencarvalho pushed a commit that referenced this pull request Apr 10, 2026
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.0.0 Issues that should be addressed for a 1.0 release! a11y Issues or PRs related to accessibility Component:Switch Spectrum CSS Status:Ready for review PR ready for review or re-review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants