Skip to content

RC #1557#1558

Merged
jason-capsule42 merged 15 commits into
mainfrom
rc/1557
Jul 16, 2026
Merged

RC #1557#1558
jason-capsule42 merged 15 commits into
mainfrom
rc/1557

Conversation

@rmenner

@rmenner rmenner commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Alaska Airlines Pull Request

Release candidate pull request. See issue #1557 for details.

Review Checklist:

  • My update follows the CONTRIBUTING guidelines of this project
  • I have performed a self-review of my own update
RC Checklist

Testing Checklist:

Browsers

Browsers Support Guide

Dev demo link

Android

  • Chrome
  • Firefox

iOS

  • Chrome
  • Firefox
  • Safari

Desktop

  • Chrome
  • Firefox
  • Safari
  • Edge

Scenarios

  • Validated linked issues with issue reporting team
  • Test coverage report review

Framework playground

  • Next React
  • SvelteKit

**By submitting this Pull Request, I confirm that my contribution is made under the terms of the Apache 2.0 license.**

Pull Requests will be evaluated by their quality of update and whether it is consistent with the goals and values of this project. Any submission is to be considered a conversation between the submitter and the maintainers of this project and may require changes to your submission.

Thank you for your submission!

-- Auro Design System Team

Summary by Sourcery

Improve combobox, dropdown, and input displayValue and focus behavior for preset values and framework integrations, and document the flight-search regressions and fixes.

Enhancements:

  • Add synthetic displayValue rendering when a combobox has a value but no selected option, ensuring preselected values are visible before options load.
  • Refine combobox focus management, including guarded focusin handling, conditional bib autofocus, and clearer focus routing to the input and clear button.
  • Make the dropdown manage trigger focus more robustly via a dedicated focusTrigger helper and a noFocusRestoreOnClose flag so consumers can own focus restoration.
  • Harden auro-input’s displayValue slot detection with null-safe checks and a light-DOM fallback so displayValue content is recognized earlier in the lifecycle.
  • Ensure the _programmaticFilterRefresh flag in the combobox is self-clearing after an update cycle to avoid suppressing the first user keystroke.

Documentation:

  • Add a detailed post-mortem documenting the displayValue and focus regressions seen in flight-search and the corresponding fixes across combobox, dropdown, and input.

Tests:

  • Extend combobox, dropdown, and input test suites to cover the new displayValue synthesis, focus routing behaviors, and slot-change handling.

jason-capsule42 and others added 15 commits July 16, 2026 12:04
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Potential fix for pull request finding Review of #1554

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Potential fix for pull request finding Review of #1554

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@rmenner
rmenner requested a review from a team as a code owner July 16, 2026 19:05
@sourcery-ai

sourcery-ai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Reviewer's Guide

Combobox, dropdown, and input components are updated to fix flight-search regressions around displayValue rendering and focus behavior, adding synthetic displayValue handling, safer focus routing, a self-clearing programmatic refresh flag, conditional bib autofocus, and more robust displayValue slot detection, with targeted tests and a post-mortem doc.

Sequence diagram for synthetic displayValue creation on preselected combobox value

sequenceDiagram
  title Synthetic displayValue handling when combobox has value but no optionSelected
  actor Consumer
  participant AuroCombobox
  participant AuroInput

  Consumer->>AuroCombobox: set value
  AuroCombobox->>AuroCombobox: updated(value)
  AuroCombobox->>AuroCombobox: updateTriggerTextDisplay()
  AuroCombobox-->>AuroCombobox: [menu.optionSelected is null and this.value is truthy]
  AuroCombobox->>AuroInput: append synthetic span slot=displayValue
  AuroCombobox->>AuroInput: checkDisplayValueSlotChange()
  AuroInput-->>AuroInput: query slot[name="displayValue"] or light DOM
  AuroInput-->>AuroInput: set hasDisplayValueContent
  AuroInput->>AuroInput: requestUpdate()
  AuroInput-->>Consumer: displayValue overlay shows raw value temporarily
Loading

Sequence diagram for focus routing on dropdown close and clear button focus

sequenceDiagram
  title Focus management when dropdown closes after option selection
  actor User
  participant AuroDropdown
  participant AuroCombobox
  participant AuroInput

  User->>AuroDropdown: select option (click)
  AuroDropdown->>AuroDropdown: handleDropdownToggle(eventType="click")
  AuroDropdown-->>AuroDropdown: isPopoverVisible = false
  AuroDropdown-->>AuroDropdown: noFocusRestoreOnClose = true
  AuroDropdown-->>AuroDropdown: [skip focusTrigger()]  
  AuroCombobox->>AuroCombobox: setClearBtnFocus()
  AuroCombobox->>AuroInput: focus()
  AuroInput-->>AuroInput: delegatesFocus to native input
  AuroCombobox->>AuroInput: query .clearBtn in shadowRoot
  AuroCombobox->>AuroInput: clearBtn.focus()
  AuroInput-->>User: focus ends on clear button instead of document.body
Loading

File-Level Changes

Change Details Files
Combobox displayValue handling now synthesizes a placeholder when value is set but no option is selected, and programmatic refresh/focus behavior is made more robust and framework-friendly.
  • Extend updateTriggerTextDisplay to append a synthetic using the raw value when optionSelected is null, and always re-evaluate auro-input’s displayValue slot via checkDisplayValueSlotChange.
  • Introduce self-clearing behavior for _programmaticFilterRefresh via updateComplete.then(), and remove scattered manual clears from updated and availableOptions handlers.
  • Guard focusin handling so combobox.focus() is only called when the host is the focus origin, preventing focus loops with shadow DOM children.
  • Adjust setClearBtnFocus to first focus the input (priming the shadow DOM focus chain) before focusing the clear button, and guard deferred setInputFocus calls so they only run when dropdown is still open.
  • Make bib input autofocus conditional on dropdownOpen && isBibFullscreen instead of static, so initial mount doesn’t steal focus.
  • Update keyboard strategy focus restoration paths to respect dropdown visibility flags and avoid fighting combobox-managed focus.
components/combobox/src/auro-combobox.js
components/combobox/test/auro-combobox.test.js
docs/post-mortem/1598671.md
Dropdown now exposes a focusTrigger helper and a noFocusRestoreOnClose flag to allow consumers to own focus restoration, and removes delegatesFocus to avoid unintended focus cascades.
  • Remove delegatesFocus from AuroDropdown’s shadowRootOptions to stop automatic focus routing at the dropdown host level.
  • Add a noFocusRestoreOnClose flag that, when true, skips generic focus restoration on close so combobox-managed focus (e.g., clear button focus) isn’t overridden.
  • Introduce focusTrigger(), which focuses the trigger wrapper if focusable or else finds slotted trigger content via slot.assignedElements and getFocusableElements, ensuring proper focus restoration for both direct and slotted triggers.
  • Update handleDropdownToggle’s close-handling paths to use focusTrigger and honor noFocusRestoreOnClose for both keydown-driven and generic close events.
  • Add tests verifying focusTrigger routes focus to slotted trigger content when the wrapper lacks tabindex, and that noFocusRestoreOnClose suppresses focus restoration.
components/dropdown/src/auro-dropdown.js
components/dropdown/test/auro-dropdown.test.js
Input displayValue slot detection is made null-safe and content-aware, ensuring hasDisplayValueContent is accurate even before shadow slot render and for synthetic or custom-element displayValue content.
  • Update checkDisplayValueSlotChange to guard shadowRoot access with optional chaining and to fall back to scanning light-DOM [slot="displayValue"] children when the shadow slot is not yet present.
  • Refine hasDisplayValueContent computation to require actual visible content (text, child elements, or shadow-rooted custom elements), avoiding treating empty forwarded slots as content that could hide synthetic displayValue placeholders.
  • Ensure changes to hasDisplayValueContent trigger requestUpdate only when the value actually changes, reducing unnecessary re-renders.
  • Adjust tests to verify that flatten:true is passed to assignedNodes and that nested slot content is correctly detected as displayValue content.
components/input/src/auro-input.js
components/input/test/auro-input.test.js
BaseInput’s delegatesFocus behavior is documented as the correct mechanism for wrapper-to-native input focus routing, clarifying that the initial-load focus theft was due to bib autofocus rather than delegatesFocus itself.
  • Update BaseInput’s shadowRootOptions comment to explain that delegatesFocus ensures clicks and programmatic focus on the wrapper reach the native input, and that initial focus issues were caused by the bib input’s static autofocus, not by delegatesFocus.
  • Leave delegatesFocus enabled on BaseInput while relying on conditional autofocus and dropdown changes to prevent focus theft on mount.
components/input/src/base-input.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot 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.

Hey - I've found 2 issues, and left some high level feedback:

  • In checkDisplayValueSlotChange, using node.shadowRoot !== null to detect custom-element content will miss closed-shadow components (where shadowRoot is always null); consider treating any ELEMENT_NODE as content (or using a different heuristic) so icons/closed-shadow components still trigger hasDisplayValueContent = true.
  • The _programmaticFilterRefresh self-clear pattern is now duplicated in both updated('value') and the availableOptions listener; consider extracting a small helper (e.g. setProgrammaticFilterRefreshOnce()) to keep this behavior centralized and reduce the risk of diverging semantics over time.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `checkDisplayValueSlotChange`, using `node.shadowRoot !== null` to detect custom-element content will miss closed-shadow components (where `shadowRoot` is always null); consider treating any `ELEMENT_NODE` as content (or using a different heuristic) so icons/closed-shadow components still trigger `hasDisplayValueContent = true`.
- The `_programmaticFilterRefresh` self-clear pattern is now duplicated in both `updated('value')` and the `availableOptions` listener; consider extracting a small helper (e.g. `setProgrammaticFilterRefreshOnce()`) to keep this behavior centralized and reduce the risk of diverging semantics over time.

## Individual Comments

### Comment 1
<location path="components/combobox/test/auro-combobox.test.js" line_range="3251-3260" />
<code_context>
+      clearBtn.focus = origFocus;
+    });
+
+    // ─── focusin handler only calls this.focus() when composedPath origin is the host ──
+    it('focusin from a shadow-DOM child does not call this.focus()', async () => {
+      const el = await defaultFixture(mobileView);
+      await elementUpdated(el);
+
+      let hostFocusCalled = false;
+      const origFocus = el.focus.bind(el);
+      el.focus = () => { hostFocusCalled = true; origFocus(); };
+
+      // Focus the internal input directly — the composed focusin event
+      // bubbles to the host with composedPath()[0] pointing at the native
+      // input inside auro-input's shadow DOM, not the combobox host.
+      // The handler should NOT call this.focus() in this case.
+      const nativeInput = el.input.shadowRoot.querySelector('input');
+      nativeInput.focus();
+      await elementUpdated(el);
+
+      expect(hostFocusCalled).to.be.false;
+
+      // Cleanup
+      el.focus = origFocus;
+    });
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a complementary test for the positive focusin case where the event originates from the combobox host.

The current test covers the negative case (focusin from a shadow-DOM child). To fully exercise the handler, please also add a test where `composedPath()[0]` is the combobox host (by focusing the host or dispatching a synthetic event) and assert that `el.focus()` is called. This will better protect against regressions if the `event.composedPath()[0] === this` condition is modified.

Suggested implementation:

```javascript
      // Cleanup
      clearBtn.focus = origFocus;
    });

    // ─── focusin handler calls this.focus() when composedPath origin is the host ──
    it('focusin from the combobox host calls this.focus()', async () => {
      const el = await defaultFixture(mobileView);
      await elementUpdated(el);

      let hostFocusCalled = false;
      const origFocus = el.focus.bind(el);
      el.focus = () => {
        hostFocusCalled = true;
        origFocus();
      };

      // Dispatch a focusin event from the host — the composedPath()[0] should be
      // the combobox host, so the handler should call this.focus().
      const focusInEvent = new FocusEvent('focusin', {
        bubbles: true,
        composed: true
      });
      el.dispatchEvent(focusInEvent);
      await elementUpdated(el);

      expect(hostFocusCalled).to.be.true;

      // Cleanup
      el.focus = origFocus;
    });


      await expect(dropdown.dropdownWidth).to.equal('400px');
    });

```

If the test suite is not already running in a browser-like environment that provides `FocusEvent`, you may need to ensure the appropriate polyfill or environment setup is in place. Also, verify that `defaultFixture` and `elementUpdated` are available in this test block and follow the same pattern as the existing negative focusin test to keep the structure consistent.
</issue_to_address>

### Comment 2
<location path="docs/post-mortem/1598671.md" line_range="216" />
<code_context>
+
+## Accompanying Test Changes
+
+Three new tests added to `components/combobox/test/auro-combobox.test.js`:
+
+1. **`programmatic value sync via syncInputValuesAcrossTriggerAndBib does not set _userTyped`** — Verifies that setting `el.value = 'Apples'` programmatically keeps `_userTyped` false (guarded by `_syncingDisplayValue` / `_programmaticFilterRefresh`), preventing the bib from auto-opening on framework bindings.
</code_context>
<issue_to_address>
**issue (typo):** Add an auxiliary verb for grammatical correctness in the tests summary sentence.

The sentence "Three new tests added to `components/combobox/test/auro-combobox.test.js`:" is missing a verb. Please revise to a grammatically complete form, such as "Three new tests were added to ..." or "Three new tests have been added to ...".

```suggestion
Three new tests were added to `components/combobox/test/auro-combobox.test.js`:
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread components/combobox/test/auro-combobox.test.js
Comment thread docs/post-mortem/1598671.md
@jason-capsule42
jason-capsule42 merged commit e2c475e into main Jul 16, 2026
83 of 84 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 6.0.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released Completed work has been released label Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released Completed work has been released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants