Back to Flet

Navigation and Routing

website/docs/cookbook/navigation-and-routing.md

0.85.0.dev26.0 KB
Original Source

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.

Routing model in Flet

A Page is a container of views (page.views), where each view represents one route-level screen.

A reliable setup uses a single source of truth: derive page.views from page.route.

Route basics

The default route is / when no route is provided.

<CodeExample path="apps/routing_navigation/initial_route/main.py" language="python" />

All routes should start with /, for example /store, /products/42, /settings/mail.

Handling route changes

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.

<CodeExample path="apps/routing_navigation/route_change_event/main.py" language="python" />

Building views from route

The pattern below is the baseline for most apps:

  1. Clear page.views.
  2. Add root view (/).
  3. Add extra views conditionally based on page.route.
  4. Handle Back in page.on_view_pop and navigate to the new top view.

:::tip[Why is this pattern important?]

  • Keeps URL, history stack, and visible UI synchronized.
  • Supports deep links and reloads naturally.
  • Makes navigation deterministic and easier to debug. :::
<CodeExample path="apps/routing_navigation/building_views_on_route_change/main.py" language="python" />

Programmatic navigation

Use page.navigate() to navigate from synchronous callbacks (e.g. on_click), or page.push_route() in async contexts:

python
# Sync (on_click, etc.)
page.navigate("/search", q="flet", page=2)

# Async
await page.push_route("/search", q="flet", page=2)

Back navigation and pop confirmation

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.

<CodeExample path="apps/routing_navigation/pop_view_confirm/main.py" language="python" />

Pop multiple views with a result

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.

<CodeExample path="apps/routing_navigation/pop_views_until/main.py" language="python" />

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" />

Route templates (parameterized routes)

Use TemplateRoute to match and parse route parameters, for example /books/:id. Template syntax is provided by repath.

python
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")

Web URL strategy

Flet web apps support two URL strategies :

  • "path" (default): in the form https://myapp.dev/store
  • "hash": https://myapp.dev/#/store

It can be set via route_url_strategy in ft.run()

python
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.

Declarative Router

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.

Practical recommendations

  • Always keep a root / view in page.views.
  • Keep route handling centralized in page.on_route_change; avoid mutating page.views from many places.
  • When adding new routes, test these cases: direct deep link, browser Back/Forward, app Back button, and reload.
  • Use route templates for dynamic segments instead of manual string splitting.