Framework7 Router: Minimal Architecture for SPA Navigation and Failure‑Safe Design
Framework7’s built‑in router lets you build a lightweight SPA with declarative routes, guard callbacks and lifecycle events. This guide shows the minimal architecture, data isolation, operational checks, failure modes, and when to redesign for larger apps.
30 Mar 2026, 01:08 UTC

Requirements
A single‑page application (SPA) built with Framework7 must provide:
- Declarative route definitions that map URLs to page components.
- Back/forward navigation that works with the browser history API.
- Guard callbacks for authentication, data pre‑fetching, or other checks.
- Lifecycle events (pageInit, pageBeforeIn, pageAfterIn, pageBeforeOut, pageAfterOut) for resource management and analytics.
- Graceful handling of navigation errors and missing components.
Minimal Viable Architecture
The smallest production‑ready layout consists of three files:
app.js– Entry point that instantiates the Framework7 app and the router.routes.js– Central JSON configuration that lists all routes, templates, and guards.- Page templates – Individual HTML or component files (e.g.,
home.html,about.html,profile.html).
Example routes.js:
export default [
{
name: 'home',
url: '/home/',
component: HomePage,
// No guard – always accessible
},
{
name: 'about',
url: '/about/',
component: AboutPage,
},
{
name: 'profile',
url: '/profile/:userId/',
component: ProfilePage,
guard: async (route, router) => {
// Mock auth check – replace with real logic
const isAuthenticated = await checkAuth();
if (!isAuthenticated) {
router.navigate('/home/');
return false; // Cancel navigation
}
return true;
},
},
];
Each component receives a data object from the router, ensuring isolation of page state.
Trust & Data Boundaries
Framework7’s router injects a router context into every page component. This context includes:
router.params– URL parameters.router.query– Query string values.- Event emitters for lifecycle hooks.
Because the router does not expose a global store, pages cannot inadvertently read or modify shared data unless a dedicated store (e.g., Vuex, Redux) is used. This design keeps each page’s data encapsulated and prevents side effects across navigation.
Operational Checks
- Route Matching – The router verifies that the URL corresponds to a defined route pattern before rendering. An unmatched URL triggers the
onPageErrorevent. - Guard Resolution – Guard callbacks must return a Promise that resolves to
trueorfalse. Afalsevalue aborts navigation and returns to the previous page. - Component Load – The router attempts to load the component’s template and script. If the component is missing or throws during initialization,
onPageErroris fired. - Memory Monitoring – Developers should check the browser’s performance panel for retained DOM nodes after
pageAfterOutevents. A leak indicates that cleanup code is missing.
Failure Modes
| Scenario | Cause | Router Response |
|---|---|---|
| Guard rejects navigation | Authentication fails | Navigation cancelled, previous page remains, onPageError not fired. |
| Missing template or script error | Router falls back to previous page, emits onPageError with error details. |
|
| Legacy browser | Polyfill required; otherwise navigation uses hash mode. |
Redesign Triggers
Consider revising the architecture when:
- Routes grow beyond 20–30 entries, making the central JSON unwieldy. Split into feature modules and lazy‑load route definitions.
- Guard callbacks become complex (e.g., multi‑step authentication). Extract guard logic into a dedicated service.
- Memory leaks are detected after repeated navigation. Ensure all event listeners are removed in
pageBeforeOutorpageAfterOut. - Deep linking is required for external traffic. Add a fallback route and ensure the router uses
pushStaterather than hash mode.
Concrete Example: Home → Profile (Guarded)
- Navigate to
/home/–pageInitfires, HomePage loads. - Click “Profile” link – router matches
/profile/123/, executes guard. - Guard resolves
true(mock auth passes) – router loadsProfilePage, triggerspageBeforeInandpageAfterIn. - Navigate back –
pageBeforeOutandpageAfterOutfire, HomePage remains in memory but is detached from the DOM. Verify no retained nodes.
When the mock auth flag is set to false, the guard redirects to /home/ and the ProfilePage never renders. This demonstrates the guard’s ability to block navigation.
Practical Verification Checklist
- Run
npm run devand openhttp://localhost:8080. - Open the browser console. Verify that
pageInitlogs appear for each navigation. - Toggle the mock auth flag and attempt to access the Profile route. Confirm redirection to Home.
- Use the Performance tab to record a navigation cycle. Look for “Detached DOM trees” after
pageAfterOut. - Delete
profile.htmltemporarily and navigate to/profile/123/. Observe theonPageErrorevent and fallback to Home.
Summary
The Framework7 router offers a lightweight, declarative navigation model that fits well into a minimal SPA architecture. By centralizing route definitions, leveraging guard callbacks, and listening to lifecycle events, developers can maintain data isolation, detect failures early, and keep memory usage under control. When the application scales or requires deeper integration (e.g., complex auth flows, large numbers of routes), modularizing routes and extracting guard logic will keep the codebase maintainable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.