Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c1dab35
chore(deps): bump @stencil/core to 4.43.4
ShaneK May 22, 2026
d6ac009
feat(input,searchbar)!: change autocorrect prop to boolean
ShaneK May 22, 2026
0c637b6
feat(angular)!: support Angular 21, drop Angular 16 and 17
ShaneK May 22, 2026
e7e54b5
fix(angular): update test tooling for Angular 18+ minimum
ShaneK May 26, 2026
53a9122
chore(angular): tighten ng21 tsconfig and document zoneless opt-out
ShaneK May 28, 2026
034efd5
chore(git): merge
ShaneK May 29, 2026
0bd395b
chore(angular): handle errors in clean-generated and update browsersl…
ShaneK May 29, 2026
74870ab
Merge branch 'major-9.0' of github.com:ionic-team/ionic-framework int…
ShaneK Jun 1, 2026
4de5689
chore(deps): bump react and vue test apps to typescript 5.9
ShaneK Jun 1, 2026
8c33698
chore(deps): bump @stencil/core to 4.43.5
ShaneK Jun 1, 2026
5d5b91b
docs(breaking): document breaking Angular 21 changes
ShaneK Jun 2, 2026
3dc3aef
fix(angular): correct ng21 import order and remove conflicting angula…
ShaneK Jun 2, 2026
df2bd72
style(react): format generated components.ts with prettier
ShaneK Jun 2, 2026
d5154cd
docs: better language
ShaneK Jun 3, 2026
3fdc66b
fix(react): pass nested overlay consumer render prop as children for …
ShaneK Jun 4, 2026
87e5eac
fix(react): externalize react and react-dom subpath imports in rollup…
ShaneK Jun 4, 2026
c7e2519
fix(angular): restore narrow per-component event types via output-tar…
ShaneK Jun 5, 2026
0b27473
docs(breaking): split input and searchbar autocorrect into separate s…
ShaneK Jun 5, 2026
1fe8a2a
Merge branch 'feat/angular-21-support' of github.com:ionic-team/ionic…
ShaneK Jun 5, 2026
25e753f
docs(breaking): fixing alphabetical order
ShaneK Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:
strategy:
fail-fast: false
matrix:
apps: [ng16, ng17, ng18, ng19, ng20]
apps: [ng18, ng19, ng20, ng21]
needs: [build-angular, build-angular-server]
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stencil-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ jobs:
strategy:
fail-fast: false
matrix:
apps: [ng16, ng17, ng18, ng19, ng20]
apps: [ng18, ng19, ng20, ng21]
needs: [build-angular, build-angular-server]
runs-on: ubuntu-latest
steps:
Expand Down
80 changes: 80 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Browser and Platform Support](#version-9x-browser-platform-support)
- [Package Exports](#version-9x-package-exports)
- [Components](#version-9x-components)
- [Input](#version-9x-input)
- [Legacy Picker](#version-9x-legacy-picker)
- [Router Outlet](#version-9x-router-outlet)
- [Searchbar](#version-9x-searchbar)
- [Select](#version-9x-select)
- [Framework Specific](#version-9x-framework-specific)
- [Angular](#version-9x-angular)
- [React](#version-9x-react)
- [Vue](#version-9x-vue)

Expand All @@ -31,7 +34,9 @@ This section details the desktop browser, JavaScript framework, and mobile platf
**Minimum JavaScript Framework Versions**
| Framework | Supported Version |
| --------- | --------------------- |
| Angular | 18+ |
| React | 18+ |
| Vue | 3.5+ |

<h2 id="version-9x-package-exports">Package Exports</h2>

Expand All @@ -52,6 +57,15 @@ Apps on `moduleResolution: "node"` (classic) and webpack 4 keep resolving throug

<h2 id="version-9x-components">Components</h2>

<h4 id="version-9x-input">Input</h4>

The `autocorrect` property on `ion-input` is now a `boolean` and defaults to `false`. It was previously typed as `'on' | 'off'` with a default of `'off'`. This resolves a type conflict introduced when TypeScript 5.9 added `autocorrect: boolean` to the DOM `HTMLElement` interface.

The string form no longer behaves the same way. Because an HTML attribute coerces to `true` for any non-empty string, `autocorrect="off"` now evaluates to `true` (autocorrect enabled). Migrate to the boolean property:

- Remove the attribute to keep autocorrect disabled (the default).
- Use a property binding to enable it: `[autocorrect]="true"` (Angular), `autocorrect={true}` (React), or `:autocorrect="true"` (Vue).

<h4 id="version-9x-legacy-picker">Legacy Picker</h4>

- `ion-picker-legacy` and `ion-picker-legacy-column` have been removed. The legacy picker component has been replaced with an inline picker component.
Expand Down Expand Up @@ -91,6 +105,15 @@ To disable the gesture on a specific outlet, set `swipeGesture` to `false`:

The `swipeBackEnabled` config option is still respected as the initial default and does not need to change for apps that set it once at startup.

<h4 id="version-9x-searchbar">Searchbar</h4>

The `autocorrect` property on `ion-searchbar` is now a `boolean` and defaults to `false`. It was previously typed as `'on' | 'off'` with a default of `'off'`. This resolves a type conflict introduced when TypeScript 5.9 added `autocorrect: boolean` to the DOM `HTMLElement` interface.

The string form no longer behaves the same way. Because an HTML attribute coerces to `true` for any non-empty string, `autocorrect="off"` now evaluates to `true` (autocorrect enabled). Migrate to the boolean property:

- Remove the attribute to keep autocorrect disabled (the default).
- Use a property binding to enable it: `[autocorrect]="true"` (Angular), `autocorrect={true}` (React), or `:autocorrect="true"` (Vue).

<h4 id="version-9x-select">Select</h4>

The `ionChange` event on `ion-select` now only fires when the selected value actually changes. Previously, the `alert` and `action-sheet` interfaces emitted `ionChange` every time the overlay was confirmed, even when the user chose the option that was already selected. This aligns the `alert` and `action-sheet` interfaces with the existing behavior of the `popover` and `modal` interfaces, and with the documented contract of `ionChange`.
Expand All @@ -99,6 +122,63 @@ Apps that relied on `ionChange` firing on every confirmation (for example, to de

<h2 id="version-9x-framework-specific">Framework Specific</h2>

<h4 id="version-9x-angular">Angular</h4>

**Minimum Angular Version**

Ionic 9 requires Angular 18 or later. Angular 16 and 17 are no longer supported.

**Angular 21 Requires Explicit Zone Change Detection**

Angular 21 defaults `bootstrapModule()` and `bootstrapApplication()` to zoneless change detection. `zone.js` in your polyfills is ignored unless you opt back in explicitly, which surfaces as runtime `NG0909` errors and breaks change detection for asynchronous updates (modal and popover lifecycle, tab navigation, and anything depending on async-resolved state). Ionic 9 relies on zone-based change detection, so apps on Angular 21 must provide it explicitly.

Standalone bootstrap:

```diff
import { bootstrapApplication } from '@angular/platform-browser';
+ import { provideZoneChangeDetection } from '@angular/core';

bootstrapApplication(AppComponent, {
providers: [
+ provideZoneChangeDetection(),
// ...other providers
],
});
```

NgModule bootstrap:

```diff
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+ import { provideZoneChangeDetection } from '@angular/core';

platformBrowserDynamic()
- .bootstrapModule(AppModule)
+ .bootstrapModule(AppModule, {
+ applicationProviders: [provideZoneChangeDetection()],
+ })
.catch((err) => console.error(err));
```

Angular forbids `provideZoneChangeDetection()` inside an NgModule's `providers` array, so for NgModule apps it must be passed as `applicationProviders` on the `bootstrapModule()` call. This step is only required on Angular 21. Angular 18 through 20 are unaffected.

**TypeScript**

Ionic 9 supports TypeScript 5.4 or later, matching the minimum for Angular 18. Angular 21 requires TypeScript 5.9 or later per Angular's own requirements.

**Module Resolution**

`@ionic/angular` is now published with `exports`-based subpath resolution. Apps using TypeScript `moduleResolution: "node"` (classic) can fail to resolve subpaths such as `@ionic/angular/standalone`. Set `moduleResolution` to `"bundler"` (the default for `ng new` on Angular 17 and later). Refer to [Package Exports](#version-9x-package-exports).

**CSS Imports No Longer Use the `~` Prefix**

Angular's current build pipeline no longer supports the webpack-loader `~` prefix in CSS `@import` statements:

```diff
- @import '~@ionic/angular/css/core.css';
+ @import '@ionic/angular/css/core.css';
```

<h4 id="version-9x-react">React</h4>

The `@ionic/react-router` package now requires React Router v6. React Router v5 is no longer supported.
Expand Down
6 changes: 3 additions & 3 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ ion-infinite-scroll-content,prop,loadingText,IonicSafeString | string | undefine
ion-input,scoped
ion-input,prop,autocapitalize,string,'off',false,false
ion-input,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false
ion-input,prop,autocorrect,"off" | "on",'off',false,false
ion-input,prop,autocorrect,boolean,false,false,false
ion-input,prop,autofocus,boolean,false,false,false
ion-input,prop,clearInput,boolean,false,false,false
ion-input,prop,clearInputIcon,string | undefined,undefined,false,false
Expand Down Expand Up @@ -1542,7 +1542,7 @@ ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocapitalize,string,'off',false,false
ion-searchbar,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,autocorrect,boolean,false,false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', arrowBackSharp) as string,false,false
ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false
ion-searchbar,prop,clearIcon,string | undefined,undefined,false,false
Expand Down Expand Up @@ -1779,7 +1779,7 @@ ion-spinner,css-prop,--color
ion-split-pane,shadow
ion-split-pane,prop,contentId,string | undefined,undefined,false,true
ion-split-pane,prop,disabled,boolean,false,false,false
ion-split-pane,prop,when,boolean | string,QUERY['lg'],false,false
ion-split-pane,prop,when,boolean | string,'(min-width: 992px)',false,false
ion-split-pane,event,ionSplitPaneVisible,{ visible: boolean; },true
ion-split-pane,css-prop,--border,ios
ion-split-pane,css-prop,--border,md
Expand Down
78 changes: 40 additions & 38 deletions core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"loader/"
],
"dependencies": {
"@stencil/core": "4.43.0",
"@stencil/core": "^4.43.5",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
Expand All @@ -81,7 +81,7 @@
"@playwright/test": "^1.59.1",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/angular-output-target": "^0.10.0",
"@stencil/angular-output-target": "^1.3.2",
"@stencil/react-output-target": "^1.5.2",
"@stencil/sass": "^3.0.9",
"@stencil/vue-output-target": "0.13.1",
Expand Down
Loading
Loading