Skip to content

bug(ngCombobox): outside-click closing is inconsistent/unreliable after a selection #33696

Description

@stijntjeleijten

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Combobox + ComboboxWidget + Listbox (the documented Select/Multiselect pattern using usePopover: 'inline' via cdkConnectedOverlay) permanently stops closing on outside click after any option has been selected once.

Root cause: the popup-close decision is only ever evaluated inside ComboboxPattern.onFocusout() (packages/aria/private), which is wired solely to the trigger element's own (focusout). Because usePopover: 'inline' renders the popup in a DOM subtree that is not a descendant of the trigger, and ngOption renders options with tabindex="-1" (which are click-focusable in browsers), clicking an option permanently moves DOM focus off the trigger and into the popup. After that, the trigger element never blurs again, so ComboboxPattern.onFocusout() never re-runs, and the popup can only be closed again by clicking the trigger directly (an unconditional toggle, unrelated to focus).

ComboboxWidget's own (focusout) (packages/aria/combobox) does fire when focus leaves the popup, and correctly updates ComboboxPopupPattern.isFocused, but nothing observes that signal to re-trigger the close check — the close logic needs to react to focus changes from either the trigger or the popup, not just the trigger.

Reproduction

The issue seems to occur on the examples from official documentation as well. So a reproduction can be found there:

  1. Open https://angular.dev/guide/aria/multiselect#basic-multiselect
  2. Click the "Select a label" combobox to open it.
  3. Click any label to select it (popup correctly stays open).
  4. Click anywhere outside the combobox (e.g. the page heading).

Expected Behavior

The popup closes

Actual Behavior

The popup stays open. Clicking outside again does nothing further. The only way to close it is to click the trigger directly

Environment

Angular CLI : 22.1.3
Angular : 22.1.0
Node.js : 24.19.0
Package Manager : npm 11.17.0
Operating System : linux x64

┌───────────────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├───────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular-devkit/architect │ 0.2201.3 │ ^0.2201.3 │
│ @angular-devkit/build-angular │ 22.1.3 │ ^22.1.3 │
│ @angular-devkit/core │ 22.1.3 │ ^22.1.3 │
│ @angular/aria │ 22.1.1 │ ^22.1.1 │
│ @angular/build │ 22.1.3 │ ^22.1.3 │
│ @angular/cdk │ 22.1.1 │ ^22.1.1 │
│ @angular/cli │ 22.1.3 │ ^22.1.3 │
│ @angular/common │ 22.1.0 │ ^22.1.0 │
│ @angular/compiler │ 22.1.0 │ ^22.1.0 │
│ @angular/compiler-cli │ 22.1.0 │ ^22.1.0 │
│ @angular/core │ 22.1.0 │ ^22.1.0 │
│ @angular/forms │ 22.1.0 │ ^22.1.0 │
│ @angular/platform-browser │ 22.1.0 │ ^22.1.0 │
│ @angular/platform-browser-dynamic │ 22.1.0 │ ^22.1.0 │
│ @angular/router │ 22.1.0 │ ^22.1.0 │
│ rxjs │ 7.8.2 │ ~7.8.0 │
│ typescript │ 6.0.3 │ ~6.0.3 │
│ vitest │ 4.1.10 │ ^4.1.10 │
└───────────────────────────────────┴───────────────────┴───────────────────┘

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: aria/comboboxgemini-triagedLabel noting that an issue has been triaged by geminineeds triageThis issue needs to be triaged by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions