Skip to content

Conversation

@ShaneK
Copy link
Member

@ShaneK ShaneK commented Jan 5, 2026

Issue number: resolves internal


What is the current behavior?

When ion-tab-bar is rapidly mounted and unmounted, a race condition in connectedCallback can cause the keyboard controller to be created after the component has been disconnected. This results in orphaned event listeners (keyboardWillShow, keyboardWillHide) on the window object that are never cleaned up, causing a memory leak.

What is the new behavior?

The keyboard controller is now properly destroyed in all scenarios:

  • If the component is disconnected while createKeyboardController is pending, the promise is tracked and destroyed when it resolves
  • If a new connectedCallback runs before the previous async completes, the stale controller is destroyed

The promise tracking pattern ensures only the most recent async operation assigns its result

Does this introduce a breaking change?

  • Yes
  • No

Other information

Current dev build:

8.7.17-dev.11767895575.16ea7cef

I was unable to find a way to create tests that accurately identified if this problem was occurring. Memory leaks are notoriously difficult to created automated tests for. I ultimately removed my previous attempts because I didn't want to give a false sense of security.

@ShaneK ShaneK requested a review from a team as a code owner January 5, 2026 17:58
@ShaneK ShaneK requested a review from thetaPC January 5, 2026 17:58
@vercel
Copy link

vercel bot commented Jan 5, 2026

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

Project Deployment Review Updated (UTC)
ionic-framework Ready Ready Preview, Comment Jan 13, 2026 10:29pm

@github-actions github-actions bot added the package: core @ionic/core package label Jan 5, 2026
}

disconnectedCallback() {
if (this.keyboardCtrlPromise) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this doesn't need to be done on this PR, but I feel like we do this same code in so many places that we should consider making it a utility.

Copy link
Member Author

Choose a reason for hiding this comment

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

It looks like this particular pattern is only specifically done in tab bar and footer (unless I'm missing something?), so I'm not sure if that's worth extracting right now

Copy link
Member

Choose a reason for hiding this comment

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

I mostly meant the code that is destroying like this:

if (this.notchController) {
this.notchController.destroy();
this.notchController = undefined;
}

We also disconnect in a lot of places:

if (this.validationObserver) {
this.validationObserver.disconnect();
this.validationObserver = undefined;
}

It seems like we could make this into a utility or something, but that's not an issue for your PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make a ticket to circle back on adding the utility.

Copy link
Member Author

Choose a reason for hiding this comment

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

@thetaPC Done! This will be FW-7030

@ShaneK ShaneK added this pull request to the merge queue Jan 14, 2026
Merged via the queue into main with commit f99d000 Jan 14, 2026
51 checks passed
@ShaneK ShaneK deleted the IONIC-82 branch January 14, 2026 16:10
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.

4 participants