angular/components · error · Error

Attempted to open an MatDatepicker with no associated input.

Error message

Attempted to open an MatDatepicker with no associated input.

What it means

open() refuses to open a datepicker that has no registered input. Material supports a programmatic-only picker, but then openedByInput must be used; a plain datepicker with no associated input cannot determine where to write values, so dev mode throws instead.

Source

Thrown at src/material/datepicker/datepicker-base.ts:652

   * @param portal Portal to be removed.
   */
  removeActions(portal: TemplatePortal): void {
    if (portal === this._actionsPortal) {
      this._actionsPortal = null;
      this._componentRef?.instance._assignActions(null, true);
    }
  }

  /** Open the calendar. */
  open(): void {
    // Skip reopening if there's an in-progress animation to avoid overlapping
    // sequences which can cause "changed after checked" errors. See #25837.
    if (this._opened || this.disabled || this._componentRef?.instance._isAnimating) {
      return;
    }

    if (!this.datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) {
      throw Error('Attempted to open an MatDatepicker with no associated input.');
    }

    this._focusedElementBeforeOpen = _getFocusedElementPierceShadowDom();
    this._openOverlay();
    this._opened = true;
    this.openedStream.emit();
  }

  /** Close the calendar. */
  close(): void {
    // Skip reopening if there's an in-progress animation to avoid overlapping
    // sequences which can cause "changed after checked" errors. See #25837.
    if (!this._opened || this._componentRef?.instance._isAnimating) {
      return;
    }

    const canRestoreFocus =
      this.restoreFocus &&

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Ensure an input with [matDatepicker]="picker" exists and is registered before calling open().
  2. If you want a calendar with no input, use the picker's programmatic-only setup (e.g. MatDatepicker with a calendar view / mat-calendar instead) rather than calling open().
  3. Guard programmatic open calls with a check that the input binding has rendered (e.g. after ViewInit / inside ngAfterViewInit or with setTimeout/afterNextRender).

Example fix

// before
click() { this.picker.open(); } // input inside *ngIf may not exist

// after
@ViewChild('picker') picker: MatDatepicker<Date>;
openPicker() {
  if (this.showInput && this.picker?.datepickerInput) this.picker.open();
}
Defensive patterns

Strategy: try-catch

Validate before calling

@ViewChild('picker') picker?: MatDatepicker<Date>;
if (this.picker && (this.picker as any).datepickerInput) { /* safe to open */ }

Type guard

function canOpen(p: MatDatepicker<Date> | undefined): p is MatDatepicker<Date> & { datepickerInput: unknown } {
  return !!p && !!(p as any).datepickerInput;
}

Try / catch

try {
  this.picker.open();
} catch (e) {
  if ((e as Error).message.includes('no associated input')) {
    console.warn('Input not rendered yet; retry after view init');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling picker.open() programmatically when no input with [matDatepicker]="picker" is registered (input not rendered yet, removed by *ngIf, or the picker never had an input and the programmatic-only flag wasn't honored).

Common situations: Opening the picker from a button click before the input's content is initialized; the input inside an *ngIf that hasn't rendered; sharing the picker reference from a detached template.

Related errors


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