Skip to main content
Version: v9

Ionic 8 から 9 へのアップデート

note

このガイドでは、アプリをすでに Ionic 8 の最新バージョンに更新していることを前提としています。このガイドを始める前に、Ionic 8 へのアップグレードガイドに従ったことを確認してください。

破壊的変更

Ionic 8 から Ionic 9 への破壊的変更の完全なリストについては、Ionic Framework リポジトリの破壊的変更ドキュメントを参照してください。

自動移行

以下の変更を手作業で進める前に、Ionic の移行ツールを実行できます。このツールはアプリをスキャンし、安全に移行できる破壊的変更を自動適用したうえで、手作業が必要な残りの更新チェックリストを出力します。各項目には影響を受けるファイル、行番号、このガイドの対応セクションへのリンクが含まれます。ツールは package.json からフレームワークとバージョンを読み取るため、アプリに関連する移行だけを適用します。

warning

まず作業内容をコミットしてください。このツールは変更をその場で書き込み、作業ツリーに未コミットの変更がある場合や Git を使用していないプロジェクトでは、--force を渡さない限り実行を拒否します。Git を使って変更を元に戻せるようにしてください。

npx @ionic/migrate

実行後、修正したものと残作業の要約を表示し、変更したファイルをプロジェクトの Prettier で整形し、何かを適用した場合は依存関係を再インストールして node_modules をバージョンバンプに合わせます。

便利なオプション:

  • --dry-run は何も書き込まず、変更予定の内容を報告します。
  • --check は報告のみ行い、まだ未完了の移行があれば非ゼロで終了します。CI 向けです。
  • --experimental は実験的な移行も実行し、レビューが必要な修正を適用します。
  • --force は作業ツリーが dirty でも、プロジェクトが git リポジトリでなくても書き込みます。
  • --no-format は変更ファイルに対する Prettier の実行をスキップします。
  • --no-install は依存関係の再インストールをスキップします。

完全な一覧は npx @ionic/migrate --help を実行してください。

このツールは一度きりの実行です。@ionic/* のバージョンをバンプすると、再実行時には新しいメジャーを検出して何もしないため、メジャーアップグレードごとに一度だけ実行し、コミット前に diff を確認してください。

はじめに

Angular

  1. Ionic 9 は Angular 18 から 22 までをサポートします。Angular 16 と 17 はサポート対象外です。Angular 更新ガイドに従って、サポート対象の Angular バージョンへ更新してください。

  2. Ionic 9 の最新バージョンにアップデートしてください:

npm install @ionic/angular@latest

Ionic Angular Server と Ionic Angular Toolkit を使用している場合は、それらも必ず更新してください:

npm install @ionic/angular@latest @ionic/angular-server@latest @ionic/angular-toolkit@latest

Zoneless 変更検出

Ionic 9 は zoneless 変更検出をサポートします。Angular 21 では zoneless がデフォルトになったため、Angular 21 以降の新しい Ionic 9 アプリは最初から Zone.js なしで動作し、変更検出用のプロバイダーは不要です。

Zone.js がない場合、非同期コールバック(オーバーレイ結果の await、setTimeout、RxJS の購読、Platform イベント)からコンポーネントの状態を更新しても、Angular は自動では再描画しません。そのような場合は、signal または ChangeDetectorRef.markForCheck() で Angular に通知する必要があります。Ionic アプリで使うパターンについては、Zoneless 変更検出を参照してください。

note

Angular 18 から 20 では、Zone.js が引き続き Angular のデフォルトのため、これらのバージョンでは影響はなく、対応は不要です。Angular 18 から 20 で zoneless を採用するには、provideZonelessChangeDetection()(Angular 18 と 19 では provideExperimentalZonelessChangeDetection())を追加し、angular.jsonpolyfills 配列から zone.js を削除してください。

Zone.js を維持する

Angular 21 以降でも Zone.js を使い続けたい場合は、provideZoneChangeDetection() でオプトインしてください。

スタンドアロンアプリケーションでは、プロバイダーを bootstrapApplication に追加します:

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

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

NgModule アプリケーションでは、bootstrapModule()applicationProviders として渡します。Angular は NgModule の providers 配列内での provideZoneChangeDetection() を許可しません:

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

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

いずれの場合も、zone.js がまだ読み込まれていることを確認してください。Angular 21 以降のデフォルトスキャフォールドでは省略されているためです。プロジェクトで使っている polyfills の設定方法に合わせて追加し直してください。

angular.json が polyfills を配列として列挙している場合は、zone.js を含めてください:

angular.json
"polyfills": ["zone.js"]

代わりに polyfills ファイルを使っている場合(たとえば Ionic スターターは "polyfills": "src/polyfills.ts" を設定します)、そこでインポートしてください:

src/polyfills.ts
import 'zone.js';

Angular 22 での OnPush 変更検出

Angular 22 では、変更検出戦略を宣言していないコンポーネントのデフォルトが OnPush に変わります。上記の zoneless デフォルトと組み合わさると、Ionic ライフサイクルフック(ionViewWillEnter など)からプレーンなフィールドとして変更したコンポーネント状態は、それだけでは再描画されなくなります。

Angular 22 へアップグレードするときは ng update を実行してください。既存コンポーネントを eager 変更検出へ移行し、以前の動作を維持します。代わりに OnPush 向けのコンポーネントを書くには、フック内で signal 経由で状態を設定するか、ChangeDetectorRef.markForCheck() を呼び出してください:

+ import { signal } from '@angular/core';
+
- entered = 0;
-
- ionViewWillEnter() {
- this.entered++;
- }
+ entered = signal(0);
+
+ ionViewWillEnter() {
+ this.entered.update((count) => count + 1);
+ }
note

Ionic 自身の Angular コンポーネントはすでに OnPush を宣言しているため、影響はありません。Angular 18 から 21 は eager デフォルトのままで、変更は不要です。

TypeScript

Ionic 9 は TypeScript 5.4 以降をサポートし、Angular 18 の最小要件と一致します。Angular 21 は TypeScript 5.9 以降、Angular 22 は TypeScript 6.0 以降が必要です。

Node.js

Angular 22 は Node.js の最小バージョンを ^22.22.3 || ^24.15.0 || ^26.0.0 に引き上げます。Angular 18 から 21 には影響ありません。

コンポーネントのインポート

Ionic 9 では、スタンドアロンコンポーネントがデフォルトのインポートパスになります。遅延読み込みコンポーネントのインポートを @ionic/angular から @ionic/angular/lazy へ変更してください。スタンドアロンコンポーネントのインポートは @ionic/angular/standalone から @ionic/angular へ変更してください。

IonicModule の非推奨化

IonicModule は Ionic 9 で非推奨となり、将来のメジャーバージョンで削除されます。引き続き完全に機能するため、直ちに対応する必要はありません。準備ができたら、スタンドアロンと NgModule ベースの両方のアプリで使える provideIonicAngular() へ移行してください。Modules から Standalone への移行を参照してください。

CSS のインポート

@ionic/angular の CSS インポートから ~ プレフィックスを削除してください。Angular の現行ビルドパイプラインは、webpack-loader のプレフィックスをサポートしなくなりました:

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

モジュール解決

アプリが TypeScript の moduleResolution: "node"(クラシック)を使用している場合、@ionic/angular/lazy のようなサブパスからのインポートが解決に失敗することがあります。tsconfig.jsonmoduleResolution"bundler" に設定してください。Angular 17 以降で ng new により作成されたアプリは、すでにこれを使用しています。

React

  1. Ionic 9 は React 18+ をサポートします。React を最新バージョンに更新してください:
npm install react@latest react-dom@latest
  1. Ionic 9 の最新バージョンにアップデートしてください:
npm install @ionic/react@latest @ionic/react-router@latest

TypeScript

@ionic/react パッケージは TypeScript 5.4 以降が必要です。型定義は TypeScript 5.4 で追加された NoInfer を使用します。

型付きオーバーレイフックの props

useIonModaluseIonPopover フックは、渡されたコンポーネントに対して componentProps を型付けするようになり、any を受け付けなくなりました。コンポーネントと一致しない props を渡すとコンパイルエラーになり、コンポーネントが必須 props を宣言している場合は componentProps が必須になります:

const Modal: React.FC<{ title: string }> = ({ title }) => <div>{title}</div>;

// Error: componentProps is required because 'title' is required
useIonModal(Modal);

// Error: 'subtitle' does not exist on the component's props
useIonModal(Modal, { title: 'Hello', subtitle: 'Nope' });

// Correct
const [present, dismiss] = useIonModal(Modal, { title: 'Hello' });

componentProps をまったく省略するとコンポーネントシグネチャが除外されるため、TypeScript は欠けている prop 名ではなく、JSX 要素シグネチャとの不一致を報告します。

これは既存の誤りを実行時ではなくビルド時に表面化するため、誤った props を渡していたアプリには新しい型エラーが出ます。呼び出し側をコンポーネントに合わせて修正してください。FC<any> として型付けされたコンポーネントは引き続き寛容なため、オーバーレイコンポーネントが型付けされていないアプリでは変更は不要です。推論に頼らず props 型を固定するには、型引数として渡してください: useIonModal<Props>(Component, props)

props の型は componentProps からではなく、コンポーネントから推論されます。インラインで定義したコンポーネントには props の注釈が必要です:

- const [present, dismiss] = useIonModal(({ name }) => <div>Hello {name}.</div>, { name: 'Dave' });
+ const [present, dismiss] = useIonModal(({ name }: { name: string }) => <div>Hello {name}.</div>, { name: 'Dave' });

移行ツールnpx @ionic/migrate --experimental で実行すると、インラインのケースに注釈を付けられます。残りの呼び出し側は書き換えではなく報告されます。正しい修正はコンポーネントが受け入れるべき内容に依存するためです。

コンポーネントではなく JSX 要素を渡す場合の動作は従来どおりです。props は要素にバインドされ、componentProps は型チェックされません。

React Router

  1. Ionic 9 は React Router 6 をサポートします。React Router のバージョン 6 に更新してください:
npm install react-router@6 react-router-dom@6
  1. @types/react-router または @types/react-router-dom をインストールしている場合は、削除してください。React Router 6 には独自の TypeScript 定義が含まれます:
npm uninstall @types/react-router @types/react-router-dom

Ionic React は React Router v6 を必須とし、v5 とは API が異なります。以下が必要な主な変更です。

ルート定義の変更

componentrender props は、JSX を受け取る element prop に置き換えられました:

- <Route path="/home" component={Home} exact />
+ <Route path="/home" element={<Home />} />

ルートはネストした children 経由でコンテンツを描画できなくなりました。ルートのコンテンツはすべて element prop 経由で渡す必要があります:

- <Route path="/">
- <Home />
- </Route>
+ <Route path="/" element={<Home />} />

Redirect の変更

<Redirect> コンポーネントは <Navigate> に置き換えられました:

- import { Redirect } from 'react-router-dom';
+ import { Navigate } from 'react-router-dom';

- <Redirect to="/home" />
+ <Navigate to="/home" replace />

ネストしたルートのパス

ネストしたルートや子の IonRouterOutlet コンポーネントを含むルートには、サブパスにマッチするよう /* サフィックスが必要です:

- <Route path="/tabs" element={<Tabs />} />
+ <Route path="/tabs/*" element={<Tabs />} />

ルートパラメータへのアクセス

ルートパラメータは props ではなく、useParams フック経由で取得します:

- import { RouteComponentProps } from 'react-router-dom';
+ import { useParams } from 'react-router-dom';

- const MyComponent: React.FC<RouteComponentProps<{ id: string }>> = ({ match }) => {
- const id = match.params.id;
+ const MyComponent: React.FC = () => {
+ const { id } = useParams<{ id: string }>();

RouteComponentProps の削除

RouteComponentProps 型と、その historylocationmatch props は React Router v6 では利用できません。代わりに同等のフックを使用してください:

  • history -> useNavigate(後述)または useIonRouter
  • match.params -> useParams(上記で説明)
  • location -> useLocation
- import { RouteComponentProps } from 'react-router-dom';
+ import { useNavigate, useLocation } from 'react-router-dom';
+ import { useIonRouter } from '@ionic/react';

- const MyComponent: React.FC<RouteComponentProps> = ({ history, location }) => {
- history.push('/path');
- history.replace('/path');
- history.goBack();
- console.log(location.pathname);
+ const MyComponent: React.FC = () => {
+ const navigate = useNavigate();
+ const router = useIonRouter();
+ const location = useLocation();
+ // In an event handler or useEffect:
+ navigate('/path');
+ navigate('/path', { replace: true });
+ router.goBack();
+ console.log(location.pathname);

exact Prop の削除

exact prop は不要になりました。React Router v6 のルートはデフォルトで正確にマッチします。サブパスにマッチさせるには、パスに /* サフィックスを付けてください:

- <Route path="/home" exact />
+ <Route path="/home" />

render Prop の削除

render prop は element prop に置き換えられました:

- <Route path="/foo" render={(props) => <Foo {...props} />} />
+ <Route path="/foo" element={<Foo />} />

プログラムによるナビゲーション

useHistory フックは useNavigate に置き換えられました:

- import { useHistory } from 'react-router-dom';
+ import { useNavigate } from 'react-router-dom';
+ import { useIonRouter } from '@ionic/react';

- const history = useHistory();
+ const navigate = useNavigate();
+ const router = useIonRouter();

- history.push('/path');
+ navigate('/path');

- history.replace('/path');
+ navigate('/path', { replace: true });

- history.goBack();
+ router.goBack();

カスタム history Prop の削除

history prop は IonReactRouterIonReactHashRouterIonReactMemoryRouter から削除されました。React Router v6 のルーターはカスタム history オブジェクトを受け付けません。

- import { createBrowserHistory } from 'history';
- const history = createBrowserHistory();
- <IonReactRouter history={history}>
+ <IonReactRouter>

IonReactMemoryRouter(テストでよく使用)では、代わりに initialEntries を使用してください:

- import { createMemoryHistory } from 'history';
- const history = createMemoryHistory({ initialEntries: ['/start'] });
- <IonReactMemoryRouter history={history}>
+ <IonReactMemoryRouter initialEntries={['/start']}>

IonRedirect の削除

IonRedirect コンポーネントは削除されました。代わりに React Router の <Navigate> コンポーネントを使用してください:

- import { IonRedirect } from '@ionic/react';
- <IonRedirect path="/old" to="/new" exact />
+ import { Navigate } from 'react-router-dom';
+ <Route path="/old" element={<Navigate to="/new" replace />} />

パスの正規表現制約の削除

React Router v6 はパスパラメータ内の正規表現制約(例: /:tab(sessions))をサポートしなくなりました。代わりにリテラルパスを使用してください:

- <Route path="/:tab(sessions)" component={SessionsPage} />
- <Route path="/:tab(sessions)/:id" component={SessionDetail} />
+ <Route path="/sessions" element={<SessionsPage />} />
+ <Route path="/sessions/:id" element={<SessionDetail />} />

IonRoute API の変更

IonRoute コンポーネントは、React Router の <Route> と同じ API 変更に従います。render prop は element に置き換えられ、exact prop は削除されました:

- <IonRoute path="/foo" exact render={(props) => <Foo {...props} />} />
+ <IonRoute path="/foo" element={<Foo />} />

React Router v5 から v6 への移行の詳細は、React Router v6 アップグレードガイドを参照してください。

Vue

  1. Ionic 9 は Vue 3.5+ をサポートします。Vue を最新バージョンに更新してください:
npm install vue@latest
  1. Ionic 9 の最新バージョンにアップデートしてください:
npm install @ionic/vue@latest @ionic/vue-router@latest

Vue Router

  1. Ionic 9 は Vue Router 5 をサポートします。Vue Router を最新バージョンに更新してください:
npm install vue-router@5

@ionic/vue-router は Vue Router v5 を必須とします。Vue Router v4 はサポート対象外です。Vue Router v5 は Vue 本体に対する peer 要件も引き上げるため、サポートされる最小の Vue バージョンは 3.5.0 になります。

Vue Router v5 は移行用リリースであり、Vue Router v4 利用者向けのランタイム破壊的変更はないため、ルート、ナビゲーションガード、IonRouterOutlet についてアプリコードの変更は不要です。

ナビゲーションガード内の next() に対する非推奨警告

Vue Router v5 は、beforeRouteLeavebeforeRouteEnterbeforeRouteUpdate、または router.beforeEach 内で next() を呼び出すと非推奨警告を出力します。コールバック形式は引き続き動作しますが、Vue Router v6 で削除されます。戻り値パターンへ移行してください:

// Composition API
onBeforeRouteLeave((to, from) => {
- if (!confirm('Leave?')) return next(false);
- next();
+ if (!confirm('Leave?')) return false;
+ return true;
});
// Options API
- beforeRouteLeave(to, from, next) {
- if (!confirm('Leave?')) return next(false);
- next();
+ beforeRouteLeave(to, from) {
+ if (!confirm('Leave?')) return false;
+ return true;
}

Vue Router v4 から v5 への移行の詳細は、Vue Router v4 から v5 への移行ガイドを参照してください。

Core

  1. Ionic 9 の最新バージョンにアップデートしてください:
npm install @ionic/core@latest

パッケージの exports

@ionic/corepackage.jsonexports フィールドを宣言するようになりました。これにより、Node ESM で @ionic/core/components@ionic/core/loader のようなサブパスが ERR_UNSUPPORTED_DIR_IMPORT で失敗する問題が修正されます。厳密な ESM リゾルバは、パッケージが以前依存していたネストした package.json ファイルを読み取らず、exports フィールドがそれらを置き換えます。これは Angular 21 のデフォルト Vitest ビルダーや生の Node などのツールチェーンに影響します。

exports フィールドはサポートされる公開エントリポイントを定義し、カバーしていないパスのインポートは失敗します。アプリが Node ESM、webpack 5、または TypeScript の moduleResolution: "bundler""node16""nodenext" を使い、未サポートのパスからインポートしている場合は、以下のいずれかのサブパスへ切り替えてください:

サブパス用途
@ionic/coreルートエントリ、コントローラ、アニメーションビルダー
@ionic/core/componentsカスタム要素のコンストラクタと共有ユーティリティ
@ionic/core/components/ion-*.js単一コンポーネントのカスタム要素コンストラクタ
@ionic/core/loaderdefineCustomElements 遅延ローダー
@ionic/core/hydrateSSR ハイドレーションエントリ
@ionic/core/css/*.cssグローバルスタイルシートとパレット

moduleResolution: "node"(クラシック)および webpack 4 のアプリは、引き続きレガシーフィールド経由で解決されるため、変更は不要です。

必須の変更

ブラウザサポート

Ionic がサポートするブラウザの一覧が変わりました。サポート対象のブラウザへアプリをデプロイしていることを確認するため、ブラウザサポートガイドを確認してください。

browserslist または .browserslistrc ファイルがある場合は、次の内容で更新してください:

Chrome >=89
ChromeAndroid >=89
Firefox >=75
Edge >=89
Safari >=16
iOS >=16

Capacitor

Ionic 9 は Capacitor 7 以降を公式にサポートします。ネイティブプラットフォーム検出は Capacitor 2 の isNative フラグへフォールバックしなくなり、isCapacitorNative は Capacitor 3 で追加された Capacitor.isNativePlatform() のみに依存します。

アプリがまだ Capacitor 2 の場合、ネイティブプラットフォーム上で動作していると検出されなくなるため、isPlatform('capacitor')isPlatform('hybrid')getPlatforms() は native ではなく web を報告します。Capacitor の更新ガイドに従って、Capacitor 7 以降へアップグレードしてください。

Img

ion-img は非推奨となり、Ionic 10 で削除されます。このコンポーネントは、ブラウザがネイティブの遅延読み込みをサポートする前に画像を遅延読み込みするために作成されました。現行のブラウザはネイティブ <img> 要素の loading="lazy" 属性をサポートするため、このコンポーネントは不要です。

ion-img をネイティブの <img> タグに置き換えてください。遅延読み込みには loading="lazy" を、ion-img がデフォルトで適用していた非同期デコードに合わせるには decoding="async" を追加してください。altsrc プロパティは、同名のネイティブ属性にそのまま対応します:

- <ion-img src="/assets/image.png" alt="Description"></ion-img>
+ <img src="/assets/image.png" alt="Description" loading="lazy" decoding="async" />

イベント

ネイティブの <img> 要素は Ionic のカスタムイベントを発行しません。代わりに標準の DOM イベントを使用してください:

ion-img eventネイティブ <img> の代替
ionImgWillLoadネイティブの同等機能はありません。画像がビューにスクロールインし、遅延読み込みが始まったときに発火していました。ネイティブの loading="lazy" ではブラウザが内部で処理します。画像がビューポートに入ろうとするタイミングを知るには、IntersectionObserver を使用してください。
ionImgDidLoadload¹
ionErrorerror¹

¹ ネイティブの loaderror はバブリングしませんが、Ionic のイベントはバブリングしていました。イベント委譲(親に 1 つのリスナー)を使っていた場合は、代わりに各 <img> でリッスンするか、キャプチャフェーズを使ってください: parent.addEventListener('load', handler, true)

スタイル

ion-img は内側の画像をスタイルするための image CSS shadow part を公開していました。ネイティブの <img> では、代わりに要素を直接スタイルしてください:

- ion-img::part(image) {
- border-radius: 8px;
- }
+ img {
+ border-radius: 8px;
+ }

Input

autocorrect プロパティの型が Boolean に変更

ion-inputautocorrect プロパティは、'on' | 'off' ではなく boolean(デフォルト false)になりました。属性は文字列 "false" 以外の任意の値で true に強制されるため、autocorrect="off" はオートコレクトを有効にします。

  • オートコレクトを無効のままにする(デフォルト)には、属性を削除してください。
  • 有効にするにはプロパティバインディングを使用してください: [autocorrect]="true"(Angular)、autocorrect={true}(React)、または :autocorrect="true"(Vue)。

フローティングラベルの動作

フローティングラベルは、入力にスロット付きコンテンツが含まれていても自動ではフロートしなくなりました。ラベルは、入力にフォーカスがあるとき、または値があるときにのみフロートします。

内部 DOM 構造の変更

内部 DOM 構造は、スロット付きコンテンツ付きのフローティングラベルをサポートするために再編成されました。

追加:

  • .input-start
  • .input-control
  • .input-end

再構成:

  • .label-text-wrapper.input-wrapper から .input-control 内へ移動
  • .native-wrapper.input-wrapper から .input-control 内へ移動
  • Start スロットは .native-wrapper から .input-start 内へ移動
  • Clear ボタンアイコンは .native-wrapper から .input-end 内へ移動
  • End スロットは .native-wrapper から .input-end 内へ移動
  • .input-control はラベルテキストとネイティブ input を含み、start/end コンテンツは専用ラッパーへ分離

これらの構造変更を考慮してセレクタを更新してください:

-ion-input .input-wrapper .native-wrapper { }
+ion-input .input-control .native-wrapper { }

-ion-input .input-wrapper .native-wrapper [slot="start"] { }
+ion-input .input-start [slot="start"] { }

-ion-input .input-wrapper .native-wrapper .input-clear-icon { }
+ion-input .input-end .input-clear-icon { }

-ion-input .input-wrapper .native-wrapper [slot="end"] { }
+ion-input .input-end [slot="end"] { }

レガシーピッカー

ion-picker-legacyion-picker-legacy-column コンポーネントは削除されました。

  • ion-picker-legacyion-picker に、ion-picker-legacy-columnion-picker-column に置き換えてください。ion-picker はオーバーレイではなくインラインで描画するため、以前の体験を維持するには ion-modal 内で提示してください。詳細は Picker in Modal のドキュメントを確認してください。
  • pickerController の使用をすべて削除してください。React を使用している場合は、useIonPicker フックの使用も削除してください。これらのコントローラベース API は削除されました。代わりに Picker コンポーネントを使用してください。
  • PickerOptionsPickerButtonPickerColumnPickerColumnOption 型エクスポートの使用をすべて削除してください。これらの型はレガシーピッカーに関連しており、削除されました。

handleBehavior のデフォルト変更

ion-modalhandleBehavior プロパティのデフォルトは、"none" ではなく "cycle" になりました。ハンドルを表示するシートモーダルでは、ハンドルがフォーカス可能になり、アクティブ化(クリック、キーボード、またはスクリーンリーダー)するとシートが利用可能なブレークポイントを循環します。これはネイティブ iOS のシート動作と一致し、支援技術ユーザー向けにシートモーダルをデフォルトで操作可能に保ちます。

ハンドルが inert であることに依存していたシートモーダルは、以前の動作を復元するために handleBehavior="none" を設定してください:

<ion-modal handle-behavior="none"></ion-modal>

ルーター統合の削除

ion-navion-router と統合しなくなりました。現在はスタンドアロンの命令型スタックナビゲーションコンポーネントであり、自身の API(rootpushpopsetRoot など)と ion-nav-link のみで駆動されます。

これは、ion-router 内に ion-nav を置き(バニラ JavaScript プロジェクト)、ルーターによる駆動に依存していたアプリにのみ影響します。ページ内のローカルなスタックナビゲーションのために単独で ion-nav を使っている場合、変更は不要です。

次の動作は削除されました:

  • ルーターは ion-nav を発見・駆動しなくなりました。ion-router 内に ion-nav を置いても、ルーティングされたアウトレットにはなりません。
  • ion-nav のナビゲート(pushpopion-nav-link、またはスワイプで戻るジェスチャ経由)は URL を更新しなくなり、ルーターのナビゲーションガードも ion-nav の遷移では実行されません。
  • setRouteId()getRouteId() メソッド、および updateURL nav オプションは削除されました。これらはルーター統合のためだけに存在していました。

ion-nav に URL 更新を依存していた場合は、代わりに URL ベースのルーティングに ion-router-outlet を使用してください。ion-route 定義はそのままにし、アウトレット要素を入れ替えてください:

<ion-router>
<ion-route url="/" component="page-one"></ion-route>
<ion-route url="/page-two" component="page-two"></ion-route>
</ion-router>

- <ion-nav></ion-nav>
+ <ion-router-outlet></ion-router-outlet>

ion-nav は、ローカルで URL なしのスタックナビゲーションのために、ルーティングされたページ内にネストしたままでも使えます。rootion-nav-link 経由で自身のスタックを管理し、push/pop しても URL は変わりません。完全な動作例は、ルーティングされたページ内での ion-nav の使用を参照してください。

Router Outlet

ion-router-outlet は、アウトレットごとにスワイプで戻るジェスチャを制御する swipeGesture プロパティを公開するようになりました。このプロパティのデフォルトは "ios" モードで true"md" モードで false です。

swipeBackEnabled 設定の動作変更

React と Vue では、swipeBackEnabled 設定オプションはアウトレットのマウント時に一度だけ読み取られるようになりました。実行時にこの設定値を動的に切り替えるアプリは、代わりに swipeGesture プロパティへ移行してください。

React:

- setupIonicReact({ swipeBackEnabled: someCondition });
+ <IonRouterOutlet swipeGesture={someCondition} />

Vue:

- createApp(App).use(IonicVue, { swipeBackEnabled: someCondition })
+ <ion-router-outlet :swipe-gesture="someCondition" />

スワイプで戻るの無効化

特定のアウトレットでジェスチャを無効にするには、swipeGesturefalse に設定してください:

<IonRouterOutlet swipeGesture={false} />

swipeBackEnabled 設定オプションは初期デフォルトとして引き続き尊重されるため、起動時に一度だけ設定するアプリでは変更不要です。

autocorrect プロパティの型が Boolean に変更

ion-searchbarautocorrect プロパティは、'on' | 'off' ではなく boolean(デフォルト false)になりました。属性は文字列 "false" 以外の任意の値で true に強制されるため、autocorrect="off" はオートコレクトを有効にします。

  • オートコレクトを無効のままにする(デフォルト)には、属性を削除してください。
  • 有効にするにはプロパティバインディングを使用してください: [autocorrect]="true"(Angular)、autocorrect={true}(React)、または :autocorrect="true"(Vue)。

Select

ionChange は値が変わったときのみ発火

ion-selectionChange イベントは、選択値が実際に変わったときのみ発火するようになりました。以前は、alertaction-sheet インターフェースは、ユーザーがすでに選択されていたオプションを選んだ場合でも、オーバーレイが確定されるたびに ionChange を発行していました。これにより、alertaction-sheet インターフェースは、既存の popovermodal インターフェースの動作、および文書化された ionChange の契約と揃います。

値変更なしの確定のたびに ionChange が発火することに依存していたアプリ(たとえば、値変更なしのオーバーレイ閉じを検出するため)は、代わりに ionDismiss をリッスンするか、基になるアラートまたはアクションシートの didDismiss イベントを使用してください。

Action Sheet インターフェースの selected ロール削除

interface="action-sheet" を使用する場合、ion-select は現在選択されているオプションのアクションシートボタンに selected ロールを割り当てなくなりました。これにより、action-sheet インターフェースは、このロールを割り当てない alertpopovermodal インターフェースと揃います。選択オプションのスタイルは変わりません。

以前は、selected ロールはセレクトの現在値に一致するオプションにだけ割り当てられていました。dismiss ロールはタップしたボタンを反映するため、これは次の 1 ケースでのみ表面化していました。すでに選択済みのオプションを再選択すると、アクションシートは ionActionSheetDidDismissrole: "selected" として閉じました。他のオプションをタップすると値が変わり、role: "" で閉じました。ロールが割り当てられなくなったため、どちらのケースも role: undefined で閉じます。値が選ばれたことを検出するためにこのロールを調べていたアプリ(たとえば、基になるアクションシートの onDidDismiss 結果から role を読む場合)は、代わりに ion-selectionChange イベントをリッスンしてください。選択が変わると選択値が発行されます。

フローティングラベルの動作

フローティングラベルは、セレクトにスロット付きコンテンツが含まれていても自動ではフロートしなくなりました。ラベルは、セレクトにフォーカスがあるとき、または値があるときにのみフロートします。さらに、フローティングラベル使用時は、セレクトにフォーカスがあるときだけプレースホルダーが表示されます。

内部 DOM 構造の変更

内部 DOM 構造は、スロット付きコンテンツ付きのフローティングラベルをサポートするために再編成されました。これにより、公開されているいくつかの shadow part の構造と位置が変わります。

追加:

  • .select-startpart="start"
  • .select-controlpart="control"
  • .select-endpart="end"

削除:

  • .select-wrapper-innerpart="inner"

再構成:

  • .label-text-wrapperpart="label" のままで、.select-wrapper から .select-control 内へ移動
  • .native-wrapperpart="container" のままで、.select-wrapper-inner から .select-control 内へ移動
  • Start スロットは .select-wrapper-inner から .select-startpart="start")内へ移動
  • End スロットは .select-wrapper-inner から .select-endpart="end")内へ移動
  • .select-iconpart="icon" のままで、位置はラベル状態に依存します:
    • start/end ラベルの場合、アイコンは .native-wrapper
    • floating/stacked ラベルの場合、アイコンは .select-end

公開された shadow part を対象とするセレクタを、新しい構造に合わせて更新してください:

現在 part="inner" を対象にしている場合、その part は削除されました。それらのスタイルを、必要に応じて新しい part を対象にするよう更新してください。

part="label"part="container"、または part="icon" を対象にしている場合、part 名は変わりませんが、shadow DOM 内の位置が変わりました。これらの part の関係やレイアウトに依存するスタイルに影響する可能性があります。

新しい構造ラッパーを対象にするには、新しい part="start"part="control"part="end" を使用してください。

Textarea

フローティングラベルの動作

フローティングラベルは、テキストエリアにスロット付きコンテンツが含まれていても自動ではフロートしなくなりました。ラベルは、テキストエリアにフォーカスがあるとき、または値があるときにのみフロートします。

内部 DOM 構造の変更

内部 DOM 構造は、スロット付きコンテンツ付きのフローティングラベルをサポートするために再編成されました。

削除: .textarea-wrapper-inner

追加: .textarea-control

名称変更:

  • .start-slot-wrapper.textarea-start
  • .end-slot-wrapper.textarea-end

再構成:

  • .label-text-wrapper.textarea-wrapper-inner から .textarea-control 内へ移動
  • .native-wrapper.textarea-wrapper-inner から .textarea-control 内へ移動
  • .start-slot-wrapper.textarea-wrapper-inner から .textarea-wrapper へ移動し、.textarea-start に名称変更
  • .end-slot-wrapper.textarea-wrapper-inner から .textarea-wrapper へ移動し、.textarea-end に名称変更

これらの構造変更を考慮してセレクタを更新してください:

-ion-textarea .textarea-wrapper-inner .native-wrapper { }
+ion-textarea .textarea-control .native-wrapper { }

-ion-textarea .start-slot-wrapper [slot="start"] { }
+ion-textarea .textarea-start [slot="start"] { }

-ion-textarea .end-slot-wrapper [slot="end"] { }
+ion-textarea .textarea-end [slot="end"] { }

最小高さの変更

Material Design(md モード)のテキストエリアの最小高さは、現在 72px です。デフォルトの行数では、これにより fill プロパティや labelPlacement に関係なくテキストエリアの高さが同じになります。以前の最小高さは次のとおりでした:

FillLabel placement以前の最小高さ
defaultstart, end, fixed44px
defaultfloating, stacked56px
solid, outlineany56px

これらは最小値であり、テキストエリアが実際に描画されていた高さではありません。start または end スロットにコンテンツがあるテキストエリアは、すでに最小値より高かったため、変更の影響は異なります。たとえば、スロット付きアイコンとボタンがある fill="solid" のテキストエリアは、以前は start ラベルで 72pxfloating ラベルで 81px で描画されていました。どちらも現在は 72px なので、floating ラベルのケースは高くなるのではなく、以前より 9px 短くなります。

72px はテキスト 2 行分より高いため、md モードでは 3 未満の rows 値はテキストエリアの高さを変えなくなります。rows="1"rows="2" はどちらも 72px で描画されます。

以前の高さに依存していた場合、または高さを rows で制御する必要がある場合は、最小高さを元に戻すよう上書きしてください。上書きはコンポーネント自身のスタイルより詳細度を高くする必要があるため、素の ion-textarea セレクタでは適用されません。詳細度を上げるために、テキストエリアにカスタムクラスを追加してください:

/* Add a custom class to the textarea */
ion-textarea.custom {
min-height: 44px;
}

アップグレードのヘルプが必要ですか?

破壊的変更の完全なリストについては、必ず Ionic 9 破壊的変更ガイドを確認してください。このアップグレードガイドは、開発者による対応が必要な変更のみを扱います。

アップグレードのヘルプが必要な場合は、Ionic Forumにスレッドを投稿してください。