Flet Routing

Deep dive · part of Python Flet

Flet apps support multi-view routing through page.route and page.on_route_change. Each route maps to a ft.View. This works the same way on desktop, mobile and the browser.

Flet apps on desktop, mobile, and web share page.route and page.on_route_change to swap views like a SPA. Each route builds a ft.View with controls; page.go('/settings') updates URL on web and internal stack elsewhere.

Clearing page.views and appending new View objects is the idiomatic pattern; forgetting page.update() leaves stale UI.

Production code combines this topic with logging, tests, and clear module boundaries so refactors stay safe when requirements grow.

page.route holds current path string including leading slash conventions.

on_route_change handler rebuilds views from scratch or selectively.

ft.View(route, controls) bundles AppBar and body for one screen.

page.go('/') navigates; initial route may come from deep link on web.

Multiple views can stack; pop patterns mimic back navigation.

ft.app(target=main) boots desktop or browser target.

Practice explaining flet routing aloud with a concrete example from your current project so the abstraction sticks beyond copy-paste exercises.

Auth-gated routes check session in route_change before building sensitive views. Query parameters on web may need manual parsing from page.route.

State carried across routes should live outside ephemeral controls—see flet-state-management.

On web, stable routes help bookmarking—branch route_change on parsed path components instead of rebuilding all views when one query param changes.

Web bookmarking needs stable routes—avoid rebuilding unrelated views when only one query parameter changes.

Read the parent tutorial on pythondeck.com for runnable snippets, then reproduce them locally in a virtual environment with pinned dependency versions matching your deployment target.

When pairing with teammates, agree on one idiomatic pattern per concern—mixed styles in one repo slow reviews and invite subtle integration bugs during merges.

Mutating controls without page.update() after route change.

Hard-coding routes in many files—centralize ROUTES dict.

Assuming desktop has browser back button without handling on_route_change.

Leaking old View references preventing GC of large images.

Implement route_change once with dispatch table {path: builder}.

Mirror web URLs in docs so testers can deep link.

Reset scroll-heavy controls when re-entering routes.

Log route changes during development to trace navigation bugs.

Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.

The program below demonstrates two routes. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# Example: Two routes
# Run in the REPL or save as a .py file and execute with python.
import flet as ft

def main(page: ft.Page):
    def route_change(_):
        page.views.clear()
        page.views.append(ft.View("/", [
            ft.AppBar(title=ft.Text("Home")),
            ft.ElevatedButton("Open settings",
                              on_click=lambda _: page.go("/settings")),
        ]))
        if page.route == "/settings":
            page.views.append(ft.View("/settings", [
                ft.AppBar(title=ft.Text("Settings")),
                ft.ElevatedButton("Back", on_click=lambda _: page.go("/")),
            ]))
        page.update()

    page.on_route_change = route_change
    page.go(page.route)

ft.app(target=main)

This sample walks through route handler in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# page.on_route_change rebuilds views when URL path changes
import flet as ft  # UI toolkit

def main(page: ft.Page):  # entry
    def route_change(_):  # handler
        page.views.clear()  # drop old views
        page.views.append(ft.View("/", [ft.Text("Home")]))  # home view
        if page.route == "/about":  # match path
            page.views.append(ft.View("/about", [ft.Text("About")]))  # about view
        page.update()  # refresh UI
    page.on_route_change = route_change  # wire
    page.go("/")  # initial navigation

print("routing wired")  # headless

Here is a hands-on illustration of go navigation. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.

# page.go updates route and triggers route_change
import flet as ft  # flet

def main(page: ft.Page):  # page
    def to_about(_): page.go("/about")  # navigate
    page.add(ft.ElevatedButton("About", on_click=to_about))  # button
    print("button added")  # log

print("handler defined")  # done

« back to Python Flet All tutorials