- framework7 + framework7-react version: 9.0.3
- "preact" 10.29.0
- Platform and Target: Framework7 React app (used from a Preact project), reproduced in browser navigation flow and observed in mobile-style router stack as well
- Live Link or CodeSandbox: not available yet, but the bug is reproducible reliably with the steps below
Describe the bug
In Framework7 React, after navigating to a subpage, going back, and then opening another subpage from the same list page, the browser URL updates to the correct target route, but the wrong page become active.
The target page is mounted in DOM, but it becomes page-previous, while the previous list page stays page-current.
To Reproduce
Steps to reproduce the behavior:
- Open a page A with links to subpages
- Open subpage B
- Go back to the "A" page
- Open subpage C
Example real flow in my app:
- Go to
/about-service/rules
- Open
/about-service/rules/user-agreement
- Tap Back
- Open
/about-service/rules/account-deletion
Expected behavior
The newly opened subpage B should become page-current, and the parent "Rules" page should become page-previous.
Actual Behavior
The browser URL changes to subpage B correctly, but the active page remains the parent "Rules" page.
The newly opened subpage B is present in DOM, but it receives the class page-previous instead of page-current.
Screenshots
I can attach a video if needed, but the DOM state after the broken transition looks like this:
- URL:
/about-service/rules/account-deletion
page-current: parent "Rules" page
page-previous: "Account deletion" page
Additional context
I traced this to framework7-react/shared/components-router.js, inside pageComponentLoader.
Current logic resolves the mounted page like this:
const pageEl = el.children[el.children.length - 1];
resolve(pageEl);
This assumes that the newly inserted page is always the last child of the router element.
That assumption breaks after a back() flow.
In my reproduction, after returning from subpage A and then opening subpage B, the children order becomes effectively:
- older previous page
- newly inserted subpage B
- current parent page ("Rules")
So el.children[el.children.length - 1] points to the old current page, not to the newly inserted page.
Because of that, router transition logic receives the wrong pageEl and animates the wrong page into page-current.
I confirmed this by instrumenting pageComponentLoader: when opening subpage B, the resolved page element was the parent "Rules" page, while the actual inserted subpage was a different child node.
Suggested fix
Instead of resolving the page as the last child, detect the newly inserted .page by diffing childrenBefore and childrenAfter.
Something like:
const childrenBefore = Array.from(routerEl.children);
function onDidUpdate(componentRouterData) {
if (componentRouterData !== viewRouter || resolved) return;
const childrenAfter = Array.from(routerEl.children);
if (hasSameChildren(childrenBefore, childrenAfter)) return;
f7events.off('viewRouterDidUpdate', onDidUpdate);
const insertedPageEl =
childrenAfter.find(
(child) => child.classList.contains('page') && !childrenBefore.includes(child)
) || el.children[el.children.length - 1];
pageData.el = insertedPageEl;
resolve(insertedPageEl);
resolved = true;
}
Workaround used locally
As a workaround, I patched pageComponentLoader at runtime and changed only the page element resolution step to select the actually inserted .page instead of the last child.
That workaround fixes the issue completely in the reproduction flow.
Investigation summary
Investigation summary:
1. Initially I suspected route guards / async route resolution.
2. After removing that variable, the issue still reproduced.
3. I narrowed it down to a simple flow:
Rules -> subpage A -> back -> subpage B
4. I reproduced it in an automated browser flow and inspected DOM classes after each transition.
5. Result:
- URL was correct
- router route was correct
- active DOM page was wrong
6. I instrumented router navigation and page loader behavior.
7. That showed `pageComponentLoader` was resolving the wrong page element after `viewRouterDidUpdate`.
8. Specifically, it resolved the last child of the view element, but after back-navigation the newly inserted page was not always the last child.
9. I patched the loader locally to resolve the actually inserted `.page` node.
10. After that, the issue disappeared in the same reproduction scenario.
Describe the bug
In Framework7 React, after navigating to a subpage, going back, and then opening another subpage from the same list page, the browser URL updates to the correct target route, but the wrong page become active.
The target page is mounted in DOM, but it becomes
page-previous, while the previous list page stayspage-current.To Reproduce
Steps to reproduce the behavior:
Example real flow in my app:
/about-service/rules/about-service/rules/user-agreement/about-service/rules/account-deletionExpected behavior
The newly opened subpage B should become
page-current, and the parent "Rules" page should becomepage-previous.Actual Behavior
The browser URL changes to subpage B correctly, but the active page remains the parent "Rules" page.
The newly opened subpage B is present in DOM, but it receives the class
page-previousinstead ofpage-current.Screenshots
I can attach a video if needed, but the DOM state after the broken transition looks like this:
/about-service/rules/account-deletionpage-current: parent "Rules" pagepage-previous: "Account deletion" pageAdditional context
I traced this to
framework7-react/shared/components-router.js, insidepageComponentLoader.Current logic resolves the mounted page like this:
This assumes that the newly inserted page is always the last child of the router element.
That assumption breaks after a
back()flow.In my reproduction, after returning from subpage A and then opening subpage B, the children order becomes effectively:
So
el.children[el.children.length - 1]points to the old current page, not to the newly inserted page.Because of that, router transition logic receives the wrong
pageEland animates the wrong page intopage-current.I confirmed this by instrumenting
pageComponentLoader: when opening subpage B, the resolved page element was the parent "Rules" page, while the actual inserted subpage was a different child node.Suggested fix
Instead of resolving the page as the last child, detect the newly inserted
.pageby diffingchildrenBeforeandchildrenAfter.Something like:
Workaround used locally
As a workaround, I patched
pageComponentLoaderat runtime and changed only the page element resolution step to select the actually inserted.pageinstead of the last child.That workaround fixes the issue completely in the reproduction flow.
Investigation summary