Skip to content

fix(modal): prevent ion-content collapsing at content-based heights - #31413

Open
brandyscarney wants to merge 21 commits into
mainfrom
FW-7731
Open

fix(modal): prevent ion-content collapsing at content-based heights#31413
brandyscarney wants to merge 21 commits into
mainfrom
FW-7731

Conversation

@brandyscarney

@brandyscarney brandyscarney commented Aug 28, 2026

Copy link
Copy Markdown
Member

Issue number: resolves #31149


What is the current behavior?

Setting --height to any of the following on an ion-modal containing an ion-content results in the ion-content collapsing to 0 height: auto, fit-content, min-content, or max-content.

What is the new behavior?

  • Checks if modal --height is set to auto, fit-content, min-content, or max-content and styles the ion-content, ion-nav and .ion-page appropriately if so
  • Watches for changes to --height on ion-modal to dynamically add and remove the class that sizes the ion-content to its content
  • Updates modal --max-height to 100% which allows the content to scroll instead of overflowing and being clipped
  • Adds a preview test for different scenarios where ion-modal has --height set
  • Adds e2e tests for the various --height scenarios

Does this introduce a breaking change?

  • Yes
  • No

Other information

Dev build: 9.0.1-dev.11788212611.154b1596

Preview: Modal: Content Height

Docs PR: ionic-team/ionic-docs#4689

@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ionic-framework Ready Ready Preview Sep 10, 2026 10:37pm UTC

Request Review

Comment thread core/src/components/content/content.tsx Outdated
}

const height = getComputedStyle(modal).getPropertyValue('--height').trim();
return CONTENT_SIZED_HEIGHTS.includes(height);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this PR is still a work in progress! 🙂

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly waiting on the breaking change question to be resolved.

Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/modal/test/content-height/modal.e2e.ts Outdated
* overlay, giving the wrapper's flex children something to shrink
* toward so `ion-content` scrolls instead of overflowing.
*/
--max-height: 100%;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this considered a breaking change since consumers are used to having it as auto?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I wouldn't consider this a breaking change because auto was never a valid value for max-height in the first place.

auto isn't listed as a valid value in the docs for max-height. As a result, max-height: auto is invalid and the property fell back to its initial value, none. If you inspect any .modal-wrapper prior to this change you will see the max-height is computed as none:

CleanShot 2026-09-02 at 16 57 53

That means the actual change is none100%.

From there, the cases where the computed value actually changes are all cases that were already broken:

  • --height: 100% (the default) and every built-in variant (calc(100% - 40px), sheet, card, inset heights) are all ≤ 100%, so the clamp has no effect and rendering remains identical.
  • The iOS card modal sets --max-height: 1000px explicitly, so it's unaffected.
  • A --height taller than the overlay (e.g. 800px in a 600px viewport, or a content-based height with tall content) previously overflowed the host. Since :host has contain: strict, that overflow was clipped at both the top and bottom, leaving some of the content unreachable. Clamping the height so ion-content scrolls instead is a fix.

Anyone who explicitly sets --max-height: auto still ends up with none, since their override is just as invalid as the old default was. And setting --max-height to anything else will still take precedence.

Additionally, CSS variable defaults are not tracked in the public API. api.txt records CSS custom property names only, so there are no generated docs or API diff changes.

Comment thread core/src/components/content/content.tsx Outdated

@thetaPC thetaPC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ShaneK ShaneK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Looks really good overall, and the test page covers a lot of ground. I did find a few cases where the content still collapses though. Setting --height from an ancestor rule, using --height: AUTO, and reconnecting across a height change all miss the class and leave a header-only modal, so the original bug is still reachable. Details in the comments, and let me know if I'm missing something!

Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/content/content.tsx Outdated
Comment thread core/src/components/modal/test/content-height/modal.e2e.ts Outdated
Comment thread core/src/components/modal/test/content-height/index.html Outdated
Comment thread core/scripts/testing/styles.css Outdated
Comment thread core/src/css/core.scss Outdated
Comment on lines +207 to +208
* Override the minimum height a flex item gets, which defaults to
* use the height of its own content. Without this, a modal sized

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Override the minimum height a flex item gets, which defaults to
* use the height of its own content. Without this, a modal sized
* Override the minimum height a flex item gets, which defaults to
* the height of its own content. Without this, a modal sized

That fixes these two lines and the dropped word. There are 19 in total though, all in the new comment blocks, spread across this file, the new test page, modal.scss and the testing stylesheet. The root .editorconfig sets trim_trailing_whitespace, and nothing catches it since prettier's globs skip scss and css.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cf43abf

Just FYI I found several other files with trailing whitespace by running npx editorconfig-checker -disable-indentation -disable-indent-size -disable-insert-final-newline -disable-end-of-line -disable-max-line-length -exclude components.d.ts src scripts. If this is something we want to enforce against we should have it covered by the linter.

CleanShot 2026-09-09 at 11 42 47

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to cover it by a linter if you want since the .editorconfig declares it. Ideally our linters would be aligned

Comment thread core/src/components/modal/test/content-height/index.html Outdated

@ShaneK ShaneK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working through all of those! Just a few things left (one of them is a reply in a thread, that's the blocker)


// The default --max-height keeps a content-sized modal inside the
// overlay. Rounded up by one, since the clamp lands on a sub-pixel.
expect(await getWrapperHeight(page)).toBeLessThanOrEqual(viewport.height + 1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one and the --max-height: 50% test below it only cap the height, they never floor it. A modal that collapsed back to a 44px header satisfies toBeLessThanOrEqual(viewport + 1), and scrollHeight > clientHeight is true at clientHeight: 0 as well, so the original bug passes both. Could they get a lower bound?

@ShaneK ShaneK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, meant to send the last one as request changes. Really it's just that one blocking change and the others are 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: ion-modal doesn't show content with auto height

3 participants