From f73878ac893e79840013d3eefd03e596e2682682 Mon Sep 17 00:00:00 2001
From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
Date: Tue, 1 Sep 2026 16:29:42 -0400
Subject: [PATCH 1/5] docs(modal): reorganize styling section to match others
---
docs/api/modal.mdx | 22 +++++++++-------------
versioned_docs/version-v6/api/modal.md | 22 ++++++++++------------
versioned_docs/version-v7/api/modal.md | 22 ++++++++++------------
versioned_docs/version-v8/api/modal.mdx | 20 +++++++-------------
4 files changed, 36 insertions(+), 50 deletions(-)
diff --git a/docs/api/modal.mdx b/docs/api/modal.mdx
index e68e3682909..6d1d20e32b3 100644
--- a/docs/api/modal.mdx
+++ b/docs/api/modal.mdx
@@ -175,34 +175,30 @@ import SheetScrollingContentExample from '@site/static/usage/v9/modal/sheet/expa
-## Styling
+## Theming
Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
-:::note
+### Styling
-If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
+Modals expose [CSS Custom Properties](#css-custom-properties) and [CSS Shadow Parts](#css-shadow-parts) for customizing their appearance.
-:::
+import ThemeExample from '@site/static/usage/v9/modal/styling/theming/index.mdx';
-:::note
+
-`ion-modal` works under the assumption that stacked modals are the same size. As a result, each subsequent modal will have no box shadow and a backdrop opacity of `0`. This is to avoid the effect of shadows and backdrops getting darker with each added modal. This can be changed by setting the `--box-shadow` and `--backdrop-opacity` CSS variables:
+### Stacked Modals
-:::
+`ion-modal` works under the assumption that stacked modals are the same size. As a result, each subsequent modal will have no box shadow and a backdrop opacity of `0`. This is to avoid the effect of shadows and backdrops getting darker with each added modal. This can be changed by setting the `--box-shadow` and `--backdrop-opacity` CSS variables:
-```
+```css
ion-modal.stack-modal {
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
```
-import ThemeExample from '@site/static/usage/v9/modal/styling/theming/index.mdx';
-
-
-
-### Animations
+## Animations
The enter and leave animations can be customized by using our animation builder and assigning animations to `enterAnimation` and `leaveAnimation`.
diff --git a/versioned_docs/version-v6/api/modal.md b/versioned_docs/version-v6/api/modal.md
index f7fb937e656..b9c95584686 100644
--- a/versioned_docs/version-v6/api/modal.md
+++ b/versioned_docs/version-v6/api/modal.md
@@ -137,30 +137,28 @@ import SheetHandleBehaviorExample from '@site/static/usage/v6/modal/sheet/handle
-## Styling
+## Theming
Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
-:::note
-If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
-:::
+### Styling
+
+import ThemeExample from '@site/static/usage/v6/modal/styling/theming/index.md';
+
+
+
+### Stacked Modals
-:::note
`ion-modal` works under the assumption that stacked modals are the same size. As a result, each subsequent modal will have no box shadow and a backdrop opacity of `0`. This is to avoid the effect of shadows and backdrops getting darker with each added modal. This can be changed by setting the `--box-shadow` and `--backdrop-opacity` CSS variables:
-:::
-```
+```css
ion-modal.stack-modal {
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
```
-import ThemeExample from '@site/static/usage/v6/modal/styling/theming/index.md';
-
-
-
-### Animations
+## Animations
The enter and leave animations can be customized by using our animation builder and assigning animations to `enterAnimation` and `leaveAnimation`.
diff --git a/versioned_docs/version-v7/api/modal.md b/versioned_docs/version-v7/api/modal.md
index a3e661af9b4..a8f19618bdb 100644
--- a/versioned_docs/version-v7/api/modal.md
+++ b/versioned_docs/version-v7/api/modal.md
@@ -161,30 +161,28 @@ import SheetHandleBehaviorExample from '@site/static/usage/v7/modal/sheet/handle
-## Styling
+## Theming
Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
-:::note
-If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
-:::
+### Styling
+
+import ThemeExample from '@site/static/usage/v7/modal/styling/theming/index.md';
+
+
+
+### Stacked Modals
-:::note
`ion-modal` works under the assumption that stacked modals are the same size. As a result, each subsequent modal will have no box shadow and a backdrop opacity of `0`. This is to avoid the effect of shadows and backdrops getting darker with each added modal. This can be changed by setting the `--box-shadow` and `--backdrop-opacity` CSS variables:
-:::
-```
+```css
ion-modal.stack-modal {
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
```
-import ThemeExample from '@site/static/usage/v7/modal/styling/theming/index.md';
-
-
-
-### Animations
+## Animations
The enter and leave animations can be customized by using our animation builder and assigning animations to `enterAnimation` and `leaveAnimation`.
diff --git a/versioned_docs/version-v8/api/modal.mdx b/versioned_docs/version-v8/api/modal.mdx
index 8f38444c646..50552c8dc75 100644
--- a/versioned_docs/version-v8/api/modal.mdx
+++ b/versioned_docs/version-v8/api/modal.mdx
@@ -175,34 +175,28 @@ import SheetScrollingContentExample from '@site/static/usage/v8/modal/sheet/expa
-## Styling
+## Theming
Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
-:::note
+### Styling
-If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
+import ThemeExample from '@site/static/usage/v8/modal/styling/theming/index.mdx';
-:::
+
-:::note
+### Stacked Modals
`ion-modal` works under the assumption that stacked modals are the same size. As a result, each subsequent modal will have no box shadow and a backdrop opacity of `0`. This is to avoid the effect of shadows and backdrops getting darker with each added modal. This can be changed by setting the `--box-shadow` and `--backdrop-opacity` CSS variables:
-:::
-
-```
+```css
ion-modal.stack-modal {
--box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
--backdrop-opacity: var(--ion-backdrop-opacity, 0.32);
}
```
-import ThemeExample from '@site/static/usage/v8/modal/styling/theming/index.mdx';
-
-
-
-### Animations
+## Animations
The enter and leave animations can be customized by using our animation builder and assigning animations to `enterAnimation` and `leaveAnimation`.
From 80cb755f362b0afea8d193f8337de956d41c1431 Mon Sep 17 00:00:00 2001
From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
Date: Tue, 1 Sep 2026 17:36:20 -0400
Subject: [PATCH 2/5] chore(deps): use dev version
---
.../stackblitz/v9/angular/package-lock.json | 14 ++++++-------
.../code/stackblitz/v9/angular/package.json | 4 ++--
.../code/stackblitz/v9/html/package-lock.json | 6 +++---
static/code/stackblitz/v9/html/package.json | 2 +-
.../stackblitz/v9/react/package-lock.json | 20 +++++++++----------
static/code/stackblitz/v9/react/package.json | 4 ++--
.../code/stackblitz/v9/vue/package-lock.json | 20 +++++++++----------
static/code/stackblitz/v9/vue/package.json | 4 ++--
8 files changed, 37 insertions(+), 37 deletions(-)
diff --git a/static/code/stackblitz/v9/angular/package-lock.json b/static/code/stackblitz/v9/angular/package-lock.json
index 88ba71f36ab..0be6ce50393 100644
--- a/static/code/stackblitz/v9/angular/package-lock.json
+++ b/static/code/stackblitz/v9/angular/package-lock.json
@@ -14,8 +14,8 @@
"@angular/platform-browser": "^22.0.0",
"@angular/platform-browser-dynamic": "^22.0.0",
"@angular/router": "^22.0.0",
- "@ionic/angular": "9.0.1",
- "@ionic/core": "9.0.1",
+ "@ionic/angular": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"ionicons": "8.1.0",
"rxjs": "^7.8.1",
"tslib": "^2.5.0"
@@ -2578,12 +2578,12 @@
}
},
"node_modules/@ionic/angular": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-q6HQdwIb5/uqZewVoBhRfz07Y9tR/cswWCY5Viy0BV5mUoLfOciAbeWqDaAK5YDc3QGZ2UH1bztsbj/VlpmOoQ==",
"license": "MIT",
"dependencies": {
- "@ionic/core": "9.0.1",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"ionicons": "^8.0.13",
"jsonc-parser": "^3.0.0",
"tslib": "^2.3.0"
@@ -2602,8 +2602,8 @@
}
},
"node_modules/@ionic/core": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-70fIYFxGuBFYOanWIl1PF3/emB+xVQjLQ9OZqgI+9ki8nEZH1y90YkTtAmleLl2jTx6TUpSaJpdUnzkBreIt7w==",
"license": "MIT",
"dependencies": {
diff --git a/static/code/stackblitz/v9/angular/package.json b/static/code/stackblitz/v9/angular/package.json
index d6cfcdf288b..1668310fc8e 100644
--- a/static/code/stackblitz/v9/angular/package.json
+++ b/static/code/stackblitz/v9/angular/package.json
@@ -15,8 +15,8 @@
"@angular/platform-browser": "^22.0.0",
"@angular/platform-browser-dynamic": "^22.0.0",
"@angular/router": "^22.0.0",
- "@ionic/angular": "9.0.1",
- "@ionic/core": "9.0.1",
+ "@ionic/angular": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"ionicons": "8.1.0",
"rxjs": "^7.8.1",
"tslib": "^2.5.0"
diff --git a/static/code/stackblitz/v9/html/package-lock.json b/static/code/stackblitz/v9/html/package-lock.json
index 6067d6733e8..1f92f7310b9 100644
--- a/static/code/stackblitz/v9/html/package-lock.json
+++ b/static/code/stackblitz/v9/html/package-lock.json
@@ -6,7 +6,7 @@
"": {
"name": "html-starter",
"dependencies": {
- "@ionic/core": "9.0.1",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"ionicons": "8.1.0"
},
"devDependencies": {
@@ -16,8 +16,8 @@
}
},
"node_modules/@ionic/core": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-70fIYFxGuBFYOanWIl1PF3/emB+xVQjLQ9OZqgI+9ki8nEZH1y90YkTtAmleLl2jTx6TUpSaJpdUnzkBreIt7w==",
"license": "MIT",
"dependencies": {
diff --git a/static/code/stackblitz/v9/html/package.json b/static/code/stackblitz/v9/html/package.json
index 136cfd7608c..22d686a2c65 100644
--- a/static/code/stackblitz/v9/html/package.json
+++ b/static/code/stackblitz/v9/html/package.json
@@ -9,7 +9,7 @@
"start": "vite preview"
},
"dependencies": {
- "@ionic/core": "9.0.1",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"ionicons": "8.1.0"
},
"devDependencies": {
diff --git a/static/code/stackblitz/v9/react/package-lock.json b/static/code/stackblitz/v9/react/package-lock.json
index 8ea6b23f5e6..47616f5ca0c 100644
--- a/static/code/stackblitz/v9/react/package-lock.json
+++ b/static/code/stackblitz/v9/react/package-lock.json
@@ -8,8 +8,8 @@
"name": "vite-react-typescript",
"version": "0.1.0",
"dependencies": {
- "@ionic/react": "9.0.1",
- "@ionic/react-router": "9.0.1",
+ "@ionic/react": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/react-router": "9.0.1-dev.11788212611.154b1596",
"@types/node": "^24.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
@@ -254,8 +254,8 @@
"license": "MIT"
},
"node_modules/@ionic/core": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-70fIYFxGuBFYOanWIl1PF3/emB+xVQjLQ9OZqgI+9ki8nEZH1y90YkTtAmleLl2jTx6TUpSaJpdUnzkBreIt7w==",
"license": "MIT",
"dependencies": {
@@ -268,12 +268,12 @@
}
},
"node_modules/@ionic/react": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/react/-/react-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/react/-/react-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-dO257Wl1RSz5g2X0uHkHZOKZYGafFPXcU0EYPgROHxKBUVZpM5VimUZVNcAjkyWRDwDyN0Bjz+7TVfCN3DDPUQ==",
"license": "MIT",
"dependencies": {
- "@ionic/core": "9.0.1",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"@stencil/react-output-target": "^1.6.2",
"ionicons": "^8.0.13",
"tslib": "*"
@@ -284,12 +284,12 @@
}
},
"node_modules/@ionic/react-router": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/react-router/-/react-router-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-+JIil95Z6jkJ5eYfTqfb0ssI2zUcONigoqvtZECUwCN56jfQLUoEvk9ZkaR0JBsjetQxltPBxdKcHbyhXPPAww==",
"license": "MIT",
"dependencies": {
- "@ionic/react": "9.0.1",
+ "@ionic/react": "9.0.1-dev.11788212611.154b1596",
"tslib": "*"
},
"peerDependencies": {
diff --git a/static/code/stackblitz/v9/react/package.json b/static/code/stackblitz/v9/react/package.json
index 45306941fb5..86864c343db 100644
--- a/static/code/stackblitz/v9/react/package.json
+++ b/static/code/stackblitz/v9/react/package.json
@@ -3,8 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@ionic/react": "9.0.1",
- "@ionic/react-router": "9.0.1",
+ "@ionic/react": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/react-router": "9.0.1-dev.11788212611.154b1596",
"@types/node": "^24.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
diff --git a/static/code/stackblitz/v9/vue/package-lock.json b/static/code/stackblitz/v9/vue/package-lock.json
index cccd51c138d..91ad8a58ec1 100644
--- a/static/code/stackblitz/v9/vue/package-lock.json
+++ b/static/code/stackblitz/v9/vue/package-lock.json
@@ -8,8 +8,8 @@
"name": "vite-vue-starter",
"version": "0.0.0",
"dependencies": {
- "@ionic/vue": "9.0.1",
- "@ionic/vue-router": "9.0.1",
+ "@ionic/vue": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/vue-router": "9.0.1-dev.11788212611.154b1596",
"vue": "^3.2.25",
"vue-router": "5.3.0"
},
@@ -63,8 +63,8 @@
}
},
"node_modules/@ionic/core": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-70fIYFxGuBFYOanWIl1PF3/emB+xVQjLQ9OZqgI+9ki8nEZH1y90YkTtAmleLl2jTx6TUpSaJpdUnzkBreIt7w==",
"license": "MIT",
"dependencies": {
@@ -77,23 +77,23 @@
}
},
"node_modules/@ionic/vue": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-CwgLj7HKBwv/xRIsXqqvHCH+QGQVMjSf3CIWbQ6x+NpnSqlj8Ve5biZwfGTL0zdd3OaclLiDkrbxMVCLHG1Ovw==",
"license": "MIT",
"dependencies": {
- "@ionic/core": "9.0.1",
+ "@ionic/core": "9.0.1-dev.11788212611.154b1596",
"@stencil/vue-output-target": "0.14.2",
"ionicons": "^8.0.13"
}
},
"node_modules/@ionic/vue-router": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-9.0.1.tgz",
+ "version": "9.0.1-dev.11788212611.154b1596",
+ "resolved": "https://registry.npmjs.org/@ionic/vue-router/-/vue-router-9.0.1-dev.11788212611.154b1596.tgz",
"integrity": "sha512-XbE++/Iepp4P3YbvMH3UX6yTJX/JLlGVOCCmcYWfQCIV7reHpwpbADxSQ/BkSyxu3oTAuaEqplhQAPPZDtFTGA==",
"license": "MIT",
"dependencies": {
- "@ionic/vue": "9.0.1"
+ "@ionic/vue": "9.0.1-dev.11788212611.154b1596"
}
},
"node_modules/@jridgewell/gen-mapping": {
diff --git a/static/code/stackblitz/v9/vue/package.json b/static/code/stackblitz/v9/vue/package.json
index fdd978c5cbb..931a5e3325a 100644
--- a/static/code/stackblitz/v9/vue/package.json
+++ b/static/code/stackblitz/v9/vue/package.json
@@ -8,8 +8,8 @@
"preview": "vite preview"
},
"dependencies": {
- "@ionic/vue": "9.0.1",
- "@ionic/vue-router": "9.0.1",
+ "@ionic/vue": "9.0.1-dev.11788212611.154b1596",
+ "@ionic/vue-router": "9.0.1-dev.11788212611.154b1596",
"vue": "^3.2.25",
"vue-router": "5.3.0"
},
From 29fb8b8b3963721f5baf864ec8dd4e8a7bec724c Mon Sep 17 00:00:00 2001
From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
Date: Tue, 1 Sep 2026 18:01:31 -0400
Subject: [PATCH 3/5] docs(modal): add Sizing to Content section and demo
---
docs/api/modal.mdx | 28 +++++++-
.../angular/example_component_css.md | 8 +++
.../angular/example_component_html.md | 32 +++++++++
.../angular/example_component_ts.md | 23 +++++++
.../modal/styling/sizing-to-content/demo.html | 67 +++++++++++++++++++
.../modal/styling/sizing-to-content/index.mdx | 35 ++++++++++
.../styling/sizing-to-content/javascript.md | 47 +++++++++++++
.../sizing-to-content/react/main_css.md | 8 +++
.../sizing-to-content/react/main_tsx.md | 63 +++++++++++++++++
.../v9/modal/styling/sizing-to-content/vue.md | 59 ++++++++++++++++
10 files changed, 369 insertions(+), 1 deletion(-)
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/angular/example_component_css.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/angular/example_component_html.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/angular/example_component_ts.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/demo.html
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/index.mdx
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/javascript.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/react/main_css.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/react/main_tsx.md
create mode 100644 static/usage/v9/modal/styling/sizing-to-content/vue.md
diff --git a/docs/api/modal.mdx b/docs/api/modal.mdx
index 6d1d20e32b3..b32123836e4 100644
--- a/docs/api/modal.mdx
+++ b/docs/api/modal.mdx
@@ -198,6 +198,32 @@ ion-modal.stack-modal {
}
```
+### Sizing to Content
+
+A modal fills the height of its container by default. Setting the `--height` CSS variable to `auto`, `fit-content`, `min-content`, or `max-content` sizes the modal to the height of what it renders instead.
+
+:::warning
+
+The height must be set on the modal through the `--height` CSS variable. Setting `height` on the `content` [CSS Shadow Part](#css-shadow-parts) will still resize the modal, but any [Content](./content) inside of it will collapse to a height of `0`, leaving only the header visible.
+
+```css
+/* Do not do this */
+ion-modal::part(content) {
+ height: fit-content;
+}
+
+/* Do this instead */
+ion-modal {
+ --height: fit-content;
+}
+```
+
+:::
+
+import SizingToContentExample from '@site/static/usage/v9/modal/styling/sizing-to-content/index.mdx';
+
+
+
## Animations
The enter and leave animations can be customized by using our animation builder and assigning animations to `enterAnimation` and `leaveAnimation`.
@@ -216,7 +242,7 @@ import CustomDialogs from '@site/static/usage/v9/modal/custom-dialogs/index.mdx'
A few things to keep in mind when creating custom dialogs:
-- `ion-content` is intended to be used in full-page modals, cards, and sheets. If your custom dialog has a dynamic or unknown size, `ion-content` should not be used.
+- `ion-content` can be used in a custom dialog, including one that is sized to its contents. The dialog's height must come from the `--height` CSS variable rather than from the dialog's children. See [Sizing to Content](#sizing-to-content).
- Creating custom dialogs provides a way of ejecting from the default modal experience. As a result, custom dialogs should not be used with card or sheet modals.
## Event Handling
diff --git a/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_css.md b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_css.md
new file mode 100644
index 00000000000..92b72024d72
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_css.md
@@ -0,0 +1,8 @@
+```css
+ion-modal {
+ --height: fit-content;
+ --width: 90%;
+ --border-radius: 8px;
+ --box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
+}
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_html.md b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_html.md
new file mode 100644
index 00000000000..3e5f8f3d892
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_html.md
@@ -0,0 +1,32 @@
+```html
+
+
+ App
+
+
+
+ Open Modal
+
+
+
+
+
+ Modal
+
+ Close
+
+
+
+
+
+ @for (item of ['Item 1', 'Item 2', 'Item 3']; track item) {
+
+ {{ item }}
+
+ }
+
+
+
+
+
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_ts.md b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_ts.md
new file mode 100644
index 00000000000..45071ee7432
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/angular/example_component_ts.md
@@ -0,0 +1,23 @@
+```ts
+import { Component } from '@angular/core';
+import {
+ IonButton,
+ IonButtons,
+ IonContent,
+ IonHeader,
+ IonItem,
+ IonLabel,
+ IonList,
+ IonModal,
+ IonTitle,
+ IonToolbar,
+} from '@ionic/angular';
+
+@Component({
+ selector: 'app-example',
+ templateUrl: 'example.component.html',
+ styleUrls: ['example.component.css'],
+ imports: [IonButton, IonButtons, IonContent, IonHeader, IonItem, IonLabel, IonList, IonModal, IonTitle, IonToolbar],
+})
+export class ExampleComponent {}
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/demo.html b/static/usage/v9/modal/styling/sizing-to-content/demo.html
new file mode 100644
index 00000000000..1d4e41b58e5
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/demo.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+ Modal | Sizing to Content
+
+
+
+
+
+
+
+
+
+
+
+ App
+
+
+
+ Open Modal
+
+
+
+
+ Modal
+
+ Close
+
+
+
+
+
+
+ Item 1
+
+
+ Item 2
+
+
+ Item 3
+
+
+
+
+
+
+
+
+
+
diff --git a/static/usage/v9/modal/styling/sizing-to-content/index.mdx b/static/usage/v9/modal/styling/sizing-to-content/index.mdx
new file mode 100644
index 00000000000..2421774fa2c
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/index.mdx
@@ -0,0 +1,35 @@
+import Playground from '@site/src/components/global/Playground';
+
+import javascript from './javascript.md';
+import vue from './vue.md';
+
+import react_main_tsx from './react/main_tsx.md';
+import react_main_css from './react/main_css.md';
+
+import angular_example_component_html from './angular/example_component_html.md';
+import angular_example_component_css from './angular/example_component_css.md';
+import angular_example_component_ts from './angular/example_component_ts.md';
+
+
diff --git a/static/usage/v9/modal/styling/sizing-to-content/javascript.md b/static/usage/v9/modal/styling/sizing-to-content/javascript.md
new file mode 100644
index 00000000000..abbaaaaa6c3
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/javascript.md
@@ -0,0 +1,47 @@
+```html
+
+
+
+
+ App
+
+
+
+ Open Modal
+
+
+
+
+ Modal
+
+ Close
+
+
+
+
+
+
+ Item 1
+
+
+ Item 2
+
+
+ Item 3
+
+
+
+
+
+
+
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/react/main_css.md b/static/usage/v9/modal/styling/sizing-to-content/react/main_css.md
new file mode 100644
index 00000000000..92b72024d72
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/react/main_css.md
@@ -0,0 +1,8 @@
+```css
+ion-modal {
+ --height: fit-content;
+ --width: 90%;
+ --border-radius: 8px;
+ --box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
+}
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/react/main_tsx.md b/static/usage/v9/modal/styling/sizing-to-content/react/main_tsx.md
new file mode 100644
index 00000000000..834160ac40d
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/react/main_tsx.md
@@ -0,0 +1,63 @@
+```tsx
+import React, { useRef } from 'react';
+import {
+ IonButton,
+ IonButtons,
+ IonContent,
+ IonHeader,
+ IonItem,
+ IonLabel,
+ IonList,
+ IonModal,
+ IonPage,
+ IonTitle,
+ IonToolbar,
+} from '@ionic/react';
+
+import './main.css';
+
+function Example() {
+ const modal = useRef(null);
+
+ function dismiss() {
+ modal.current?.dismiss();
+ }
+
+ return (
+
+
+
+ App
+
+
+
+
+ Open Modal
+
+
+
+
+
+ Modal
+
+ dismiss()}>Close
+
+
+
+
+
+ {['Item 1', 'Item 2', 'Item 3'].map((item) => (
+
+ {item}
+
+ ))}
+
+
+
+
+
+ );
+}
+
+export default Example;
+```
diff --git a/static/usage/v9/modal/styling/sizing-to-content/vue.md b/static/usage/v9/modal/styling/sizing-to-content/vue.md
new file mode 100644
index 00000000000..33dedffb3ad
--- /dev/null
+++ b/static/usage/v9/modal/styling/sizing-to-content/vue.md
@@ -0,0 +1,59 @@
+```vue
+
+
+
+
+
+ App
+
+
+
+ Open Modal
+
+
+
+
+ Modal
+
+ Close
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+```
From 9856417dce090f91c8d29a5cf149302484340ed3 Mon Sep 17 00:00:00 2001
From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
Date: Tue, 1 Sep 2026 18:02:39 -0400
Subject: [PATCH 4/5] docs(modal): specify inline modals can be overridden per
component
---
docs/api/modal.mdx | 4 +++-
versioned_docs/version-v6/api/modal.md | 4 +++-
versioned_docs/version-v7/api/modal.md | 4 +++-
versioned_docs/version-v8/api/modal.mdx | 4 +++-
4 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/docs/api/modal.mdx b/docs/api/modal.mdx
index b32123836e4..f33bb98b4fa 100644
--- a/docs/api/modal.mdx
+++ b/docs/api/modal.mdx
@@ -177,7 +177,9 @@ import SheetScrollingContentExample from '@site/static/usage/v9/modal/sheet/expa
## Theming
-Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
+[Controller modals](#controller-modals) are appended to the root of your application, outside of the component that presented them. Component-scoped styles will not reach these modals, so their styles must be applied globally, from a stylesheet that is not scoped to a component.
+
+[Inline modals](#inline-modals-recommended) stay where they are declared in your template, so component-scoped styles do apply to them.
### Styling
diff --git a/versioned_docs/version-v6/api/modal.md b/versioned_docs/version-v6/api/modal.md
index b9c95584686..dc2b196678e 100644
--- a/versioned_docs/version-v6/api/modal.md
+++ b/versioned_docs/version-v6/api/modal.md
@@ -139,7 +139,9 @@ import SheetHandleBehaviorExample from '@site/static/usage/v6/modal/sheet/handle
## Theming
-Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
+[Controller modals](#controller-modals) are appended to the root of your application, outside of the component that presented them. Component-scoped styles will not reach these modals, so their styles must be applied globally, from a stylesheet that is not scoped to a component.
+
+[Inline modals](#inline-modals-recommended) stay where they are declared in your template, so component-scoped styles do apply to them.
### Styling
diff --git a/versioned_docs/version-v7/api/modal.md b/versioned_docs/version-v7/api/modal.md
index a8f19618bdb..38391cc9237 100644
--- a/versioned_docs/version-v7/api/modal.md
+++ b/versioned_docs/version-v7/api/modal.md
@@ -163,7 +163,9 @@ import SheetHandleBehaviorExample from '@site/static/usage/v7/modal/sheet/handle
## Theming
-Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
+[Controller modals](#controller-modals) are appended to the root of your application, outside of the component that presented them. Component-scoped styles will not reach these modals, so their styles must be applied globally, from a stylesheet that is not scoped to a component.
+
+[Inline modals](#inline-modals-recommended) stay where they are declared in your template, so component-scoped styles do apply to them.
### Styling
diff --git a/versioned_docs/version-v8/api/modal.mdx b/versioned_docs/version-v8/api/modal.mdx
index 50552c8dc75..f352f77999c 100644
--- a/versioned_docs/version-v8/api/modal.mdx
+++ b/versioned_docs/version-v8/api/modal.mdx
@@ -177,7 +177,9 @@ import SheetScrollingContentExample from '@site/static/usage/v8/modal/sheet/expa
## Theming
-Modals are presented at the root of your application so they overlay your entire app. This behavior applies to both inline modals and modals presented from a controller. As a result, custom modal styles can not be scoped to a particular component as they will not apply to the modal. Instead, styles must be applied globally. For most developers, placing the custom styles in `global.css` is sufficient.
+[Controller modals](#controller-modals) are appended to the root of your application, outside of the component that presented them. Component-scoped styles will not reach these modals, so their styles must be applied globally, from a stylesheet that is not scoped to a component.
+
+[Inline modals](#inline-modals-recommended) stay where they are declared in your template, so component-scoped styles do apply to them.
### Styling
From 8af88249e92bbbb7ca1889d3523056cfcfa1b8f3 Mon Sep 17 00:00:00 2001
From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
Date: Wed, 2 Sep 2026 15:06:49 -0400
Subject: [PATCH 5/5] docs(modal): update content links and comment
---
docs/api/modal.mdx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/api/modal.mdx b/docs/api/modal.mdx
index f33bb98b4fa..c42f823e770 100644
--- a/docs/api/modal.mdx
+++ b/docs/api/modal.mdx
@@ -127,7 +127,7 @@ import CardExample from '@site/static/usage/v9/modal/card/basic/index.mdx';
:::info
-[Content](./content) should be used inside of the sheet modal if you want your modal content to be scrollable.
+[Content](./content.mdx) should be used inside of the sheet modal if you want your modal content to be scrollable.
:::
@@ -206,10 +206,10 @@ A modal fills the height of its container by default. Setting the `--height` CSS
:::warning
-The height must be set on the modal through the `--height` CSS variable. Setting `height` on the `content` [CSS Shadow Part](#css-shadow-parts) will still resize the modal, but any [Content](./content) inside of it will collapse to a height of `0`, leaving only the header visible.
+The height must be set on the modal through the `--height` CSS variable. Setting `height` on the `content` [CSS Shadow Part](#css-shadow-parts) will still resize the modal, but any [Content](./content.mdx) inside of it will collapse to a height of `0`, leaving only the header visible.
```css
-/* Do not do this */
+/* DO NOT DO THIS */
ion-modal::part(content) {
height: fit-content;
}