Framework7 page:init never fires: router and page lifecycle diagnostic guide
Blank Framework7 pages and a missing page:init event usually mean the router cannot identify the page node. This guide maps symptoms to causes, gives ordered checks for data-page, router config and DOM7 timing, and ties each finding to a fix.
22 Sept 2026, 19:56 UTC

After navigating to a route in Framework7 v5–v7, the target page stays blank or shows the previous page, and your listener for page:init never runs. The useful takeaway is that Framework7 fires page lifecycle events only for a page that sits inside a View's pages container with a valid data-page attribute and a matching router entry. If any of those conditions is missing, the router still animates something, but the lifecycle never starts.
Recognizable condition
The condition is consistent: a link or app.views.main.router.navigate() call changes the URL, the view animates, but the new content is empty, stale, or unstyled. In DevTools, a listener attached to the page element for page:init is never invoked. This differs from a rendering bug where the event fires but the data is missing.
Note the version assumption. Framework7 v5–v7 use page:init, page:mounted and similar colon-separated names. Framework7 v4 used pageInit. Page lifecycle events only fire for pages inside a View's pages container; modals, popups and panels require explicit initialization.
Cause and diagnostic table
| Symptom clue | Likely cause | Why it blocks page:init |
|---|---|---|
No data-page on the outer div of the template | Missing or misspelled data-page attribute | Router cannot identify the page node to bind lifecycle |
| Navigation succeeds but the console warns about a missing route | ignoreMissingPages:true in router init | Router skips page creation and does not emit lifecycle |
| AJAX or Template7 HTML inserted after navigation starts | Template not processed by DOM7 before showPage | Page node is not in the View's pages container when the router checks |
| Two routes or templates share the same page name or path | Duplicate page names or routes | Router confusion; event delegation attaches to the wrong node |
Ordered checks
Confirm the navigation target matches the page name. Compare the link
href="#detail"or the callapp.views.main.router.navigate('/detail/')against the route definition and the template'sdata-page. The names must correspond exactly, including case.Inspect the rendered HTML before the transition completes. In DevTools Elements, locate the View's pages container, typically
.view-main .pages. Verify the target template contains an outer div such as<div class="page" data-page="detail">and that it exists in the DOM before the router shows the page.Review router parameters in the Framework7 init call. Check the router options for
ignoreMissingPages. If it istrue, the router will not error on missing routes but also will not create a page node.Look for console warnings about duplicate routes or missing templates. Duplicate definitions often appear as a warning that a route with a given path already exists.
If you use async Template7 or AJAX loading, verify timing. The template promise must resolve and the HTML must be appended to the View's pages element before
router.navigateorshowPageruns. Mixing Framework7's DOM7$$with plain jQuery selectors can break event delegation.
Fixes tied to findings
Missing data-page
Add the correct attribute to the outer page div in the template:
<div class="page" data-page="detail">
<div class="navbar">...</div>
<div class="page-content">...</div>
</div>Risk: renaming a page requires updating every link and route definition that references it.
ignoreMissingPages enabled
Set the option to false or add a matching route:
routes: [
{ path: '/detail/', url: './pages/detail.html' }
]With ignoreMissingPages:false the router blocks navigation when the route is absent, which makes the problem visible instead of silent.
AJAX template not processed
When you load HTML yourself, insert it with DOM7 and make sure it lands inside the View's pages container before navigation:
const html = await fetch('./pages/detail.html').then(r => r.text());
$$('.view-main .pages').append(html);Call app.views.main.router.navigate('/detail/') only after the container exists. Do not use jQuery $ to manipulate Framework7 page nodes.
Duplicate page names or routes
Rename pages or use unique route paths. Ensure each data-page value is unique within the app and each route path is unique.
Async template delay
Await the template promise before calling navigate. If you must navigate first, load the template in the route's beforeEnter hook and return a promise that resolves after insertion.
Verification
Create a minimal app with two pages using the CDN links for Framework7 v7. Navigate from home to detail via a link or router.navigate('/detail/'). In the DevTools Console, add a temporary listener:
$$('.page[data-page="detail"]').on('page:init', function (e) {
console.log('page:init fired', e.target);
});Expected check: the listener logs when the page becomes active and the content renders. Apply each fix in turn and observe whether the event fires and the content renders correctly. This example is illustrative; run it in your own project and confirm the output yourself rather than assuming the logged values.
Limitations and escalation
This guide covers router-driven pages inside a View. It does not cover pages rendered in popups, modals or panels, which require explicit initialization such as app.popup.create. It also assumes v5–v7 event naming; on v4 the event names differ.
Escalate to the Framework7 community or open a GitHub issue when the page still does not initialize after applying all fixes, when behavior is inconsistent across devices or Framework7 versions, when you observe memory leaks or repeated page:init events without navigation, or when the problem persists after you build a minimal reproducible example that isolates the router and page template.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.