ionic-team / ionic-team/ionic-framework

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

Open
#30,694 1 comment 0 reactions 0 assignees View on GitHub
ionitron: needs reproduction
Dominant language
TypeScript
Stars
52.7k
Forks
13.3k
Avg merge
1d 15h
Merged PRs (30d)
51

Description

### Prerequisites

- [x] I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#creating-an-issue).
- [x] I agree to follow the [Code of Conduct](https://ionicframework.com/code-of-conduct).
- [x] I have searched for [existing issues](https://github.com/ionic-team/ionic-framework/issues) that already report this problem, without success.

### 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 `` (outside any popover) that shows the current month.
An `` that contains ` `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):
```


{{ label }}: {{ format(value) }}


@if (open) {


}

```

### 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_

Contributor guide

Open the contributing guide

Research direction

Start with the Angular standalone component imports and bootstrap/APP_INITIALIZER setup described in the issue, then reproduce the MonthPicker from the linked gist on Capacitor iOS. Check when customElements.get(...) becomes truthy and hosts receive the hydrated class; done means ion-chip and deferred ion-datetime are defined and styled without manual defineCustomElement() calls or hidden instances.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, ios, typescript
Domain
frontend, mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.