Skip to content

fix(combobox, breadcrumbs): propagate lang/dir for a single item's language without breaking layout#6496

Open
majornista wants to merge 3 commits into
mainfrom
mijordan/SWC-2359-combobox-lang-of-parts
Open

fix(combobox, breadcrumbs): propagate lang/dir for a single item's language without breaking layout#6496
majornista wants to merge 3 commits into
mainfrom
mijordan/SWC-2359-combobox-lang-of-parts

Conversation

@majornista

Copy link
Copy Markdown
Contributor

Description

Adds "language of parts" support to sp-combobox and sp-breadcrumbs: consumers can set lang/dir on an individual slotted item (e.g. a language name rendered in its own script) and have it render correctly, without breaking the surrounding component's layout.

  • Combobox: a slotted <sp-menu-item lang="he" dir="rtl"> (or a ComboboxOption with lang/dir) now propagates those attributes to its rendered counterpart in the popover. The text input itself also adopts the lang of the currently-selected option, so screen readers pronounce the displayed value correctly.
  • Breadcrumbs: the same propagation applies to items collapsed into the "More items" overflow menu.
  • BreadcrumbItem: lang/dir now apply only to #item-link (the text), not the host — so one item's language doesn't flip its own layout or its separator's chevron relative to its siblings. The chevron now tracks the ambient direction (nearest ancestor's dir, or the document default) instead of the item's own dir attribute, and stays correct if an ancestor's dir changes after the item has already mounted, or for the overflow-menu wrapper item (which is rendered inside Breadcrumbs' own shadow root rather than as a light-DOM child).

Two non-obvious base-class behaviors caused regressions mid-implementation and are now specifically guarded against (with tests that fail without the fix):

  • SpectrumElement overrides the native dir getter to return computed CSS direction rather than the attribute, so authored dir values must be read via getAttribute('dir').
  • CSS :dir() resolves directionality via the DOM's dir attribute chain, entirely independent of the direction property — so direction: inherit alone doesn't stop a mismatched attribute from being picked up by descendant :dir() selectors.

Motivation and context

Combobox and Breadcrumbs synthesize new elements from extracted data (rather than reusing the original slotted elements) when rendering their popover/overflow menu, so any lang/dir set on the original item was silently dropped — breaking pronunciation and bidi text shaping for mixed-language lists (e.g. a language picker).

Related issue(s)

  • fixes SWC-2359

Screenshots (if appropriate)

N/A — no visual/layout changes to default (single-language) usage. New Storybook stories (languageOfParts, LanguageOfParts) demonstrate the fix; a screenshot/VRT baseline update may be worth attaching before merge.

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed 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. (not yet added — flagging before merge)
  • I have included updated documentation if my change required it. (no MDX/README changes made; consider a note in each component's docs)

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

  • Combobox popover items and input keep an item's own language

    1. Go to Storybook → Combobox → languageOfParts
    2. Open the combobox and inspect each option in devtools
    3. Expect each <sp-menu-item> in the popover to carry the same lang/dir as its source; select the Hebrew or Arabic option and expect the input's own lang attribute to update to match
  • Breadcrumbs overflow menu keeps an item's own language

    1. Go to Storybook → Breadcrumbs → LanguageOfParts (forces the overflow menu via max-visible-items)
    2. Open the "More items" menu and inspect the items in devtools
    3. Expect each <sp-menu-item> to carry the same lang/dir as the source <sp-breadcrumb-item>
  • A single item's language doesn't break the breadcrumb trail's layout

    1. In the LanguageOfParts story, locate the Hebrew/Arabic breadcrumb items amid the (LTR) trail
    2. Expect their separators (chevrons) to point the same direction as their LTR siblings, not mirrored
    3. Toggle dir="rtl" on <sp-breadcrumbs> via devtools after the story has rendered
    4. Expect all separators (including the "More items" wrapper's, if overflowed) to mirror correctly

Device review

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

Accessibility testing checklist

  • Keyboard (required — document steps below)

    1. Go to Storybook → Combobox → languageOfParts
    2. Tab to the combobox, press ArrowDown to open, arrow through options, press Enter to select a non-Latin-script option (e.g. עברית)
    3. Expect focus to return to the input with the selected value displayed; no change in tab order or focus trapping from the lang/dir changes
  • Screen reader (required — document steps below)

    1. With a screen reader active, open Storybook → Combobox → languageOfParts and arrow through the popover options
    2. Expect each option (including עברית, العربية) to be announced using that language's pronunciation rules, not the page's default language
    3. Select a non-Latin option and expect the combobox's announced value to use the same correct pronunciation
    4. Repeat for Storybook → Breadcrumbs → LanguageOfParts, opening the "More items" overflow menu

@majornista majornista requested a review from a team as a code owner July 10, 2026 20:54
@majornista majornista added bug Something isn't working a11y Issues or PRs related to accessibility Component:Combobox Component:Breadcrumbs 1st-gen labels Jul 10, 2026
@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e4a0924

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

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

@github-actions

Copy link
Copy Markdown
Contributor

📚 Branch Preview Links

🔍 Gen1 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-6496

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.

@coveralls

coveralls commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 29130699021

Coverage increased (+0.008%) to 96.265%

Details

  • Coverage increased (+0.008%) from the base build.
  • Patch coverage: 121 of 121 lines across 3 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 39304
Covered Lines: 38038
Line Coverage: 96.78%
Relevant Branches: 6485
Covered Branches: 6041
Branch Coverage: 93.15%
Branches in Coverage %: Yes
Coverage Strength: 462.96 hits per line

💛 - Coveralls

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds “language of parts” support to 1st-gen sp-combobox and sp-breadcrumbs by propagating per-item lang/dir into internally-rendered menu items, and by scoping sp-breadcrumb-item’s lang/dir so a single item’s language doesn’t flip breadcrumb layout/separators.

Changes:

  • Combobox: propagate option lang/dir into rendered popover items and sync the input’s lang to the committed selection.
  • Breadcrumbs: propagate item lang/dir into overflow menu items; adjust sp-breadcrumb-item so separators mirror based on ambient direction rather than the item’s own dir.
  • Add targeted tests and Storybook stories demonstrating mixed lang/dir lists, plus update 1st-gen version typings.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
1st-gen/tools/base/src/version.d.ts Updates declared versions to match implementation.
1st-gen/packages/combobox/test/combobox-a11y.test.ts Adds coverage for lang/dir propagation and input lang syncing.
1st-gen/packages/combobox/stories/combobox.stories.ts Adds languageOfParts story demonstrating per-item language/direction.
1st-gen/packages/combobox/src/Combobox.ts Implements option lang/dir forwarding and input lang binding.
1st-gen/packages/breadcrumbs/test/breadcrumbs.test.ts Adds overflow menu propagation tests and ancestor dir-change regression test.
1st-gen/packages/breadcrumbs/test/breadcrumb-item.test.ts Adds tests ensuring per-item dir doesn’t break layout and separators track ambient direction.
1st-gen/packages/breadcrumbs/stories/breadcrumbs.stories.ts Adds LanguageOfParts story for overflow menu propagation.
1st-gen/packages/breadcrumbs/src/Breadcrumbs.ts Captures per-item lang/dir and forwards into overflow menu items.
1st-gen/packages/breadcrumbs/src/BreadcrumbItem.ts Scopes lang/dir onto #item-link and computes separator direction from ambient context with ancestor observation.
1st-gen/packages/breadcrumbs/src/breadcrumb-item.css Ensures host layout direction inherits ambient direction even when host has dir.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread 1st-gen/packages/breadcrumbs/src/BreadcrumbItem.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.

Comment thread 1st-gen/packages/combobox/src/Combobox.ts Outdated
Comment thread 1st-gen/packages/breadcrumbs/test/breadcrumb-item.test.ts Outdated
Comment thread 1st-gen/packages/breadcrumbs/test/breadcrumb-item.test.ts Outdated
Comment thread 1st-gen/packages/breadcrumbs/test/breadcrumb-item.test.ts Outdated
@majornista majornista requested a review from Copilot July 10, 2026 21:58
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 90ccb0c to a77171e Compare July 10, 2026 22:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Comment thread 1st-gen/packages/breadcrumbs/src/Breadcrumbs.ts
Comment thread 1st-gen/packages/breadcrumbs/src/Breadcrumbs.ts Outdated
@majornista majornista requested a review from Copilot July 10, 2026 22:04
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 0377af4 to 3c7d781 Compare July 10, 2026 22:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Comment thread 1st-gen/packages/breadcrumbs/src/breadcrumb-item.css Outdated
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 3c7d781 to ff9409d Compare July 10, 2026 22:28
@majornista majornista requested a review from Copilot July 10, 2026 22:29
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from c017bce to 0e255f5 Compare July 10, 2026 22:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Comment thread 1st-gen/packages/combobox/test/combobox-a11y.test.ts Outdated
Comment thread 1st-gen/packages/breadcrumbs/test/breadcrumbs.test.ts Outdated
@majornista majornista requested a review from Copilot July 10, 2026 22:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Comment thread 1st-gen/packages/combobox/stories/combobox.stories.ts
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 0e255f5 to 6ed624c Compare July 10, 2026 22:41
@majornista majornista requested a review from Copilot July 10, 2026 22:41
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from f9d6e3c to 9e1bdb7 Compare July 10, 2026 22:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Comment thread 1st-gen/packages/breadcrumbs/test/breadcrumbs.test.ts Outdated
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 7e29d47 to d3afc71 Compare July 10, 2026 23:05
@majornista majornista requested a review from Copilot July 10, 2026 23:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Comment thread 1st-gen/packages/breadcrumbs/src/BreadcrumbItem.ts Outdated
Comment thread 1st-gen/packages/breadcrumbs/src/BreadcrumbItem.ts Outdated
…nguage without breaking layout

Previously, setting `lang`/`dir` on a slotted `<sp-menu-item>` (Combobox)
or `<sp-breadcrumb-item>` (Breadcrumbs) had no effect on the rendered
popover/overflow-menu counterpart, since both components synthesize new
elements from extracted data rather than reusing the originals.

- Combobox: forwards `lang`/`dir` from slotted items (or `.options` data)
  onto the rendered popover `<sp-menu-item>`, and now syncs the input's
  own `lang` to the committed option's language for correct pronunciation.
- Breadcrumbs: same propagation for the "More items" overflow menu.
- BreadcrumbItem: forwards `lang`/`dir` to `#item-link` only, so a single
  item's language does not flip its own layout or its separator's
  mirrored chevron. The separator now explicitly tracks the *ambient*
  direction (nearest ancestor `dir`, or the document default) instead of
  inheriting the host's own `dir` attribute via `:dir()`, including live
  updates when an ancestor's `dir` changes after mount, and across the
  shadow-root boundary for the overflow-menu wrapper item.

Along the way, worked around two non-obvious base-class behaviors that
caused regressions mid-fix: `SpectrumElement` overrides `dir` to return
computed CSS direction rather than the attribute (must read
`getAttribute('dir')` for authored values), and CSS `:dir()` resolves
directionality via the attribute chain, independent of the `direction`
property.

Adds Storybook stories (`languageOfParts` / `LanguageOfParts`) and test
coverage for each fix, each verified to fail without its corresponding
code change.

Jira: SWC-2359
@majornista majornista force-pushed the mijordan/SWC-2359-combobox-lang-of-parts branch from 207a4ec to 6ee4b1a Compare July 10, 2026 23:22
@majornista majornista requested a review from Copilot July 10, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.

Comment thread 1st-gen/packages/combobox/src/Combobox.ts Outdated
// `SpectrumElement` overrides `dir` to return the *computed* CSS
// direction rather than the attribute, so read the attribute
// directly to capture the item's own authored direction override.
dir: (el.getAttribute('dir') as 'ltr' | 'rtl' | 'auto') || undefined,
Comment on lines +157 to +163
dir=${ifDefined(
(this.getAttribute('dir') || undefined) as
| 'ltr'
| 'rtl'
| 'auto'
| undefined
)}
Comment thread 1st-gen/packages/combobox/test/combobox-a11y.test.ts
Comment thread 1st-gen/packages/combobox/test/combobox-a11y.test.ts
Michael Jordan and others added 2 commits July 10, 2026 19:35
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1st-gen a11y Issues or PRs related to accessibility bug Something isn't working Component:Breadcrumbs Component:Combobox

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants