website/docs/cookbook/navigation-and-routing.md
import {CodeExample} from '@site/src/components/crocodocs';
Navigation and routing is the core of building multi-screen Flet apps.
It lets you organize your UI into virtual pages (View objects),
keep URL/history in sync, and support deep links to specific app states.
This page focuses on the current routing model and maintained examples.
A Page is a container of views (page.views), where each view represents one route-level screen.
page.route is the current route string (for example /, /store, /settings/mail).page.views is the active navigation stack.page.on_route_change rebuilds the stack when route changes.page.on_view_pop handles Back navigation (system Back, AppBar Back, browser Back).A reliable setup uses a single source of truth: derive page.views from page.route.
The default route is / when no route is provided.
All routes should start with /, for example /store, /products/42, /settings/mail.
Whenever route changes (URL edit, browser Back/Forward, or app navigation),
page.on_route_change event is triggered.
Use this event as the place where you decide which views must exist for the current route.
The pattern below is the baseline for most apps:
page.views./).page.route.page.on_view_pop and navigate to the new top view.:::tip[Why is this pattern important?]
Use page.navigate() to navigate from synchronous callbacks
(e.g. on_click), or page.push_route() in async contexts:
# Sync (on_click, etc.)
page.navigate("/search", q="flet", page=2)
# Async
await page.push_route("/search", q="flet", page=2)
When users go back, Flet triggers page.on_view_pop.
For flows requiring confirmation (for example, unsaved changes), disable automatic pop
and confirm manually with View.can_pop + View.on_confirm_pop.
When a multi-step flow finishes deep in the view stack, use
page.pop_views_until()
to jump back to a target route and deliver a result to the destination view
via page.on_views_pop_until.
Routing composes well with navigation controls such as drawer, rail, and tabs. This example shows route-driven drawer navigation with multiple top-level destinations:
<CodeExample path="apps/routing_navigation/drawer_navigation/main.py" language="python" />Use TemplateRoute to match and parse route parameters, for example /books/:id.
Template syntax is provided by repath.
import flet as ft
troute = ft.TemplateRoute(page.route)
if troute.match("/books/:id"):
print("Book ID:", troute.id)
elif troute.match("/account/:account_id/orders/:order_id"):
print("Account:", troute.account_id, "Order:", troute.order_id)
else:
print("Unknown route")
Flet web apps support two URL strategies :
"path" (default): in the form https://myapp.dev/store"hash": https://myapp.dev/#/storeIt can be set via route_url_strategy in ft.run()
import flet as ft
ft.run(main, route_url_strategy="hash")
For Flet server deployments, you can also set the FLET_ROUTE_URL_STRATEGY
environment variable.
For declarative apps using @component, Flet provides a
Router system inspired by React Router. It handles
nested routes, layout routes with outlets, dynamic segments, data loaders,
and active link detection — all without manual route matching.
With manage_views=True, Router can also manage the view stack directly,
enabling swipe-back gestures and AppBar back buttons on mobile. Route
components return View objects with their own
AppBar, and navigating deeper pushes views
onto the stack.
See the Router cookbook for a complete guide.
/ view in page.views.page.on_route_change; avoid mutating page.views from many places.