Choosing a Routing Strategy in Framework7: Native Router vs Framework-Specific Wrappers
A decision guide for picking between Framework7's native router and framework-specific wrappers (Vue Router, React Router, Svelte Router). Covers constraints, trade-offs, implementation patterns, and verification steps to avoid dual-router conflicts.
13 Jul 2026, 14:15 UTC

The Problem: Two Navigation Stacks Don't Mix
Framework7 applications need a single source of truth for navigation. If you instantiate both Framework7's built-in router and a framework-specific router (Vue Router, React Router, or Svelte Router), you end up with competing navigation stacks, duplicate page loads, and broken back-button behavior. The decision isn't about which router is "better"—it's about which integration model matches your stack and whether you can commit to one navigation authority.
Decision and Constraints
Choose Framework7's native router when:
- You're building a vanilla Framework7 app or a Framework7-first project
- You need tight integration with native components: sheet modals, popovers, popups, and page transitions
- You want zero-config deep linking and a built-in page cache
Choose a framework-specific router when:
- Your team already standardizes on Vue 3, React 18, or Svelte 5
- You need framework-native state management (Vuex/Pinia, Redux/Zustand, Svelte stores)
- You share routing logic across multiple Framework7-based projects
Hard constraints: Framework7 ≥ 6.0, Vue 3+, React 18+, Svelte 5+. Framework7 7.0 introduced async component loading—older router configs will break. Mixing routers in one app is unsupported and causes duplicate navigation events.
Supported Options at a Glance
| Option | Framework | Integration Level | Key Features |
|---|---|---|---|
| Framework7 Router | Vanilla / Framework7 | Core | Native page stack, modal support, deep linking |
| Vue Router | Vue 3 | Wrapper via @framework7/vue | Reactive state, Pinia/Vuex integration |
| React Router | React 18 | Wrapper via @framework7/react | React hooks, Context API |
| Svelte Router | Svelte 5 | Wrapper via @framework7/svelte | Svelte stores, reactivity |
Trade-offs
Native Router Advantages
- Seamless navigation transitions—pages slide, modals animate, back gestures work without extra code
- Built-in page caching (
keepAliveroutes) preserves scroll position and component state - Single navigation stack eliminates race conditions between hash/history modes
Framework Router Advantages
- Framework-native reactivity: a Vue counter component keeps its value across route changes without manual preservation
- Ecosystem tooling: Vue DevTools route inspection, React Router's
useNavigate, Svelte'sgoto - Shared routing modules across Framework7 and non-Framework7 projects in a monorepo
Performance Note
For apps under ~20 routes, differences are negligible. In complex flows (nested tabs, dynamic imports, guarded routes), the native router avoids double-rendering because it controls the DOM directly. Framework wrappers add a thin reconciliation layer—measure with performance.mark around navigation if latency matters.
Concrete Implementation: Native Router (Vanilla JS)
Run this in a browser environment with Framework7 7.x loaded via ES module or CDN. Requires a root element #app in your HTML.
// app.js
import Framework7 from 'framework7/bundle';
import 'framework7/css/bundle';
const app = new Framework7({
root: '#app',
routes: [
{
path: '/',
componentUrl: './pages/home.html',
options: { keepAlive: true }
},
{
path: '/about',
componentUrl: './pages/about.html'
},
{
path: '/settings',
component: (resolve) => {
import('./pages/settings.js').then((mod) => resolve({ default: mod.default }));
}
}
],
// Enable hash routing for static hosting; use history for server-configured apps
router: { browserHistory: false }
});
// Navigate programmatically
app.router.navigate('/about');
Key points: componentUrl loads HTML partials; component with dynamic import enables code-splitting (Framework7 7.0+). keepAlive caches the home page instance. Set browserHistory: true only if your server rewrites all routes to index.html.
Concrete Implementation: Vue 3 Integration
Run in a Vite/Vue 3 project with @framework7/vue installed. This example assumes you want Vue Router to own navigation while Framework7 provides UI components.
// main.js
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { Framework7Vue } from '@framework7/vue';
import App from './App.vue';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/about', component: () => import('./views/About.vue') }
]
});
const app = createApp(App);
app.use(Framework7Vue); // No router passed—Framework7 uses Vue Router
app.use(router);
app.mount('#app');
In App.vue, use <f7-view main> with <router-view> inside. Framework7's View component detects Vue Router and defers navigation to it. Do not pass a router option to Framework7Vue—that would instantiate the native router alongside Vue Router.
Verification Checklist
- Native router test: Open the vanilla app, navigate Home → About → Back. Confirm slide transition, no console errors, and the Home page retains scroll position (due to
keepAlive). - Vue Router test: Add a
refcounter inHome.vue, increment it, navigate to About, return. Counter value must persist—proves Vue component instance reuse. - Duplicate event check: Open DevTools Console, filter for "route" or "navigation". Each navigation should emit exactly one
routeChange(native) orrouter.on('routeChanged')(Vue). Two events = dual routers active. - Network tab: Verify each route's component chunk loads once per session (native) or once per visit (framework router with default caching).
Limitations and Gotchas
- Framework7 7.0 async components: Old synchronous
component: MyComponentsyntax throws. Must use dynamicimport()orcomponentUrl. - Vue 2 / React 17: Not supported by current wrappers. Polyfills won't fix missing composition API or concurrent features.
- Hash vs history mode mismatch: If Framework7 uses hash (
browserHistory: false) but Vue Router uses history, deep links break. Align both or use one router. - Modal routes: Native router supports
/modal/:idthat opens a sheet. Framework routers need custom route guards to replicate this—adds boilerplate.
How to Decide Today
If you're starting fresh with no framework allegiance, use the native router. It's the path of least resistance for Framework7's mobile-first UX. If your organization has standardized on Vue/React/Svelte and you need shared routing modules, adopt the wrapper—but audit the codebase to ensure no legacy Framework7 router instantiation remains. Run the verification checklist before shipping.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.