angular/components · error · Error

Cannot retrieve popup content because the combobox is closed

Error message

Cannot retrieve popup content because the combobox is closed or not associated with a popup controls ID.

What it means

The combobox harness's getPopupWidget method reads the host element's 'aria-controls' attribute to locate the popup widget element by ID. When the combobox is closed (or was never wired to a popup), no aria-controls is present, so the harness cannot resolve the popup element and throws this error instead of returning null.

Source

Thrown at src/aria/combobox/testing/combobox-harness.ts:57

        async (harness, disabled) => (await harness.isDisabled()) === disabled,
      );
  }

  /**
   * Gets the component harness for the active widget contained inside the popup.
   * Use this when you need to access the harness of the widget itself (e.g., `ListboxHarness`),
   * rather than querying items within it.
   * @param type The harness type to locate. Must implement standard static `.with()` method.
   */
  async getPopupWidget<T extends ComponentHarness>(
    type: ComponentHarnessConstructor<T> & {
      with: (options?: {selector?: string}) => HarnessPredicate<T>;
    },
  ): Promise<T> {
    const host = await this.host();
    const controlsId = await host.getAttribute('aria-controls');
    if (!controlsId) {
      throw new Error(
        'Cannot retrieve popup content because the combobox is closed or not associated with a popup controls ID.',
      );
    }
    return this.documentRootLocatorFactory().locatorFor(type.with({selector: `#${controlsId}`}))();
  }

  /**
   * Gets a harness loader scoped to the content inside the popup container.
   * Note that lookups performed by this loader will only find descendants of the popup container.
   */
  async getPopupLoader(): Promise<HarnessLoader> {
    return this.getRootHarnessLoader();
  }

  /** Overrides root loader to automatically resolve queries nested inside the associated popup. */
  protected override async getRootHarnessLoader(): Promise<HarnessLoader> {
    const host = await this.host();
    const controlsId = await host.getAttribute('aria-controls');

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Open the combobox before querying the popup (e.g. await harness.open() or dispatch interaction on the trigger) so aria-controls is set.
  2. Verify the combobox component sets aria-controls on its host pointing at the popup element's ID.
  3. Await open state: check await harness.isOpen() before calling getPopupWidget.
  4. If using a custom combobox, ensure ngComboboxWidget assigns the popup an ID and links it via aria-controls.

Example fix

// before
const popup = await harness.getPopupWidget({selector: '.my-options'});
// after
await harness.open();
const popup = await harness.getPopupWidget({selector: '.my-options'});
Defensive patterns

Strategy: validation

Validate before calling

const host = await harness.host();
if (!(await host.getAttribute('aria-controls'))) {
  await harness.open(); // or fail fast
}

Type guard

async function popupAvailable(harness: {host(): Promise<any>}): Promise<boolean> {
  return !!(await (await harness.host()).getAttribute('aria-controls'));
}

Try / catch

try {
  const popup = await harness.getPopupWidget();
} catch (e) {
  if ((e as Error).message.includes('Cannot retrieve popup content')) {
    await harness.open();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling harness.getPopupWidget(...) (or getPopupLoader/getRootHarnessLoader) while the combobox popup is closed, or on a custom combobox whose host element never sets aria-controls to the popup's ID.

Common situations: Tests that query popup options without first opening the combobox (e.g. missing an open()/click on the trigger); custom combobox implementations that omit the aria-controls wiring the Angular ARIA combobox pattern requires; popup unmounted after close so the attribute is removed.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/ffb3226b717b62ad. Report an issue: GitHub.