Repository navigation
bug: ion-datetime datetime-ready gets stuck after the element is relocated in the DOM, so it never re-initializes on re-show #31281
Description
Prerequisites
- I have read the Contributing Guidelines.
- I agree to follow the Code of Conduct.
- I have searched for existing issues that already report this problem, without success.
Ionic Framework Version
v8.x
Current Behavior
If a single ion-datetime element is reused across presentations by moving it between DOM parents (i.e. it gets disconnectedCallback → connectedCallback between shows), the calendar/wheel stops repainting its selection on the second and every subsequent show. activeParts is correct and reset(startDate) is being called with a valid date, but the previously-selected day is not rendered as selected, and the calendar isn't scroll-positioned to the working month. A forced layout reflow (e.g. resizing the window) makes the selection appear.
Expected Behavior
After the element is hidden and shown again - including when it has been relocated in the DOM between shows - the datetime should re-initialize and render its current selection, without needing an external reflow.
Steps to Reproduce
Self-contained repro (single HTML file, CDN, no build) is attached below. It keeps one <ion-datetime> and moves it between a visible container and a hidden pool (display: none) - a disconnect + connect on each open, calling reset('2026-07-10') each time, as an app would.
- Open → the 10th is rendered selected.
- Close, then Open again → the 10th is no longer rendered selected; the calendar is unstyled/stale, even though
reset()ran andactivePartsis correct. - Open (with workaround) → clearing
datetime-readybefore showing restores the selection.
Important: do not inspect the element in devtools between steps, and don't resize the window - either forces a layout reflow that repaints the selection and masks the bug.
The stuck state is observable without forcing layout (a classList read doesn't reflow):
// element parked in the hidden pool after one show:
datetimeEl.classList.contains('datetime-ready'); // true - should be false while hiddenCode Reproduction URL
Everything is in index.html
Ionic Info
Ionic:
Ionic CLI : 7.2.1 (/opt/homebrew/lib/node_modules/@ionic/cli)
Capacitor:
Capacitor CLI : 8.3.4
@capacitor/android : 8.3.4
@capacitor/core : 8.3.4
@capacitor/ios : 8.3.4
Utility:
cordova-res : not installed globally
native-run : not installed globally
System:
NodeJS : v26.5.0 (/opt/homebrew/Cellar/node/26.5.0/bin/node)
npm : 11.17.0
OS : macOS Unknown
Additional Information
Root cause
The lazy-ready path added in 8.8.0 tracks readiness with hasBeenIntersecting / markReady() and gates re-initialization on the datetime-ready class. Line references are core/src/components/datetime/datetime.tsx at v8.8.14:
disconnectedCallback()(:1113) setsthis.hasBeenIntersecting = false(:1119).- The hidden-state IntersectionObserver callback bails early on
if (!this.hasBeenIntersecting)(:1250) before reachingthis.el.classList.remove('datetime-ready')(:1267) - the guard added in fix(datetime): prevent hidden-state observer from tearing down ready class on initial entry #31108 (8.8.6). - So an element disconnected while it had been shown keeps
datetime-readyset even though it's now hidden. - On the next show,
connectedCallback()(:1106) →ensureReadyIfVisible()(:1109) early-returns onif (this.el.classList.contains('datetime-ready')) return(:1154), andmarkReady()(:1166) early-returns the same way (:1167). SoinitializeListeners()(:1170 → :1139) →initializeCalendarListener()(:1140, defined :902) never runs again. That listener scroll-positions the working month and lets the calendar paint, so the render is left stale.
In short: disconnectedCallback clears hasBeenIntersecting (:1119), which makes the hidden observer skip clearing datetime-ready (guard :1250 before :1267), which makes the next show skip re-initialization (:1154 / :1167).
Workaround
Remove the class immediately before re-showing so the ready path runs again:
datetimeEl.classList.remove('datetime-ready');Suggested fix
Have the hidden-state observer (or disconnectedCallback) clear datetime-ready when the element is torn down, so a subsequent show goes through markReady() / initializeCalendarListener() again. The hasBeenIntersecting guard from #31108 shouldn't leave the ready class set on an element that has been disconnected.
Activity
ShaneK commentedon Aug 16, 2026
Hey @nf-matt! Your analysis was spot on, the
hasBeenIntersectingreset indisconnectedCallbackwas exactly the problem.This is already fixed. #31335 dropped that line and went out in
8.8.18, same root cause as #31155 and #31143.I tried your scenario on current
mainto be sure, moving one datetime between a visible host and adisplay: nonepool. Thedatetime-readyclass clears on every hide now, and the selection and month position come back on each re-show. Our v9 branch has the same code, so it's fixed there too.Closing this out, but if you're on
8.8.18and still hitting it please reopen and I'll take another look. Thanks for the writeup, the line references made this really easy to check!ionitron-bot commentedon Sep 15, 2026
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.