Skip to content

bug: Capacitor iOS: Ionic custom elements not defined early enough when first used via standalone components — <ion-chip> outside popover renders unstyled; <ion-datetime> in popover looks inert until explicit defineCustomElement() calls #30694

@sachithd

Description

@sachithd

Prerequisites

Ionic Framework Version

v8.x

Current Behavior

On iOS (device/simulator), Ionic web components aren’t defined/hydrated early enough when used via Angular standalone components. My page renders a custom MonthPicker component:
An <ion-chip> (outside any popover) that shows the current month.
An <ion-popover> that contains <ion-datetime presentation="month-year"> and opens when the chip is clicked.
In Safari/macOS (ionic serve) everything looks correct.
In Capacitor iOS, the chip renders unstyled (no “pill” look, grey text, tight spacing) and the datetime in the popover appears disabled/unstyled. The hosts never get the hydrated class.
If I manually define the custom elements at bootstrap:

import { defineCustomElement as defineIonChip } from '@ionic/core/components/ion-chip.js';
import { defineCustomElement as defineIonIcon } from '@ionic/core/components/ion-icon.js';
import { defineCustomElement as defineIonLabel } from '@ionic/core/components/ion-label.js';
import { defineCustomElement as defineIonPopover } from '@ionic/core/components/ion-popover.js';
import { defineCustomElement as defineIonDatetime } from '@ionic/core/components/ion-datetime.js';
import { defineCustomElement as defineIonModal } from '@ionic/core/components/ion-modal.js';

defineIonChip(); defineIonIcon(); defineIonLabel();
defineIonPopover(); defineIonDatetime(); defineIonModal();

…everything works on iOS (chip gets pill styling; datetime works and looks correct).
I also tried an APP_INITIALIZER that import()s the components and importing the Angular standalone wrappers (IonChip, IonDatetime, etc.) — neither fixed it. Only the explicit defineCustomElement() calls or rendering a hidden one-time instance in the app shell “warms up” the components.

Actual behavior (iOS only)
ion-chip renders as plain/un-hydrated element (no pill styles).
ion-datetime in popover looks disabled/unstyled.
customElements.get('ion-chip') / get('ion-datetime') are falsy at first render; hosts lack hydrated class.
Works instantly after calling defineCustomElement() for the components (or rendering one hidden instance at app root).

Workarounds
Explicitly call defineCustomElement() for ion-chip, ion-icon, ion-label, ion-popover, ion-datetime (and ion-modal if used) at app bootstrap.
Alternatively, render a hidden one-off instance in the app shell to force definition.

Notes
Global Ionic CSS + theme variables are present.
The same code path in Safari desktop works; issue is specific to iOS/WKWebView + initial definition timing.
Using Angular standalone imports for IonChip/IonDatetime did not auto-define the underlying custom elements on iOS in this setup.

Expected Behavior

Ionic Angular should ensure the underlying web components are defined/hydrated when used via standalone components, even if the first usage of some components is:
outside the initial template but within a child/feature component, or
inside a popover/modal that’s created later.

Steps to Reproduce

Custom MonthPicker (chip triggers a popover that contains datetime):

<ion-chip [id]="triggerId">
  <ion-icon name="calendar-outline" color="primary"></ion-icon>
  <ion-label>{{ label }}: {{ format(value) }}</ion-label>
</ion-chip>

<ion-popover
  [trigger]="triggerId"
  triggerAction="click"
  side="bottom"
  alignment="center"
  (ionPopoverDidPresent)="open = true"
  (ionPopoverDidDismiss)="open = false"
>
  <ng-template>
    @if (open) {
      <ion-datetime
        presentation="month-year"
        [value]="valueIso"
        [min]="minIso"
        [max]="maxIso"
        [showDefaultButtons]="true"
        (ionChange)="onChange($event.detail.value)">
      </ion-datetime>
    }
  </ng-template>
</ion-popover>

Code Reproduction URL

https://gist.github.com/sachithd/e7e229b3056d1991e884d98514fa931a

Ionic Info

Ionic:

Ionic CLI : 7.2.1 (/Users/creativedev/.nvm/versions/node/v22.19.0/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 8.7.3
@angular-devkit/build-angular : 20.2.1
@angular-devkit/schematics : 20.2.1
@angular/cli : 20.2.1
@ionic/angular-toolkit : 12.3.0

Capacitor:

Capacitor CLI : 7.4.3
@capacitor/android : 7.4.3
@capacitor/core : 7.4.3
@capacitor/ios : 7.4.3

Utility:

cordova-res : not installed globally
native-run : 2.0.1

System:

NodeJS : v22.19.0 (/Users/creativedev/.nvm/versions/node/v22.19.0/bin/node)
npm : 11.6.0
OS : macOS Unknown

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions