Routing¶
FluxUI has a built-in SPA router. Navigating between pages does not reload the browser —
it sends a navigate event over the WebSocket and the server renders the new page
into the existing shell.
Declaring Pages¶
Use the @app.page(path) decorator to register a page handler:
import fluxui as ui
app = ui.App("My App")
@app.page("/")
def home(session):
ui.Heading("Home", level=1)
ui.Link("Go to about", href="/about")
@app.page("/about")
def about(session):
ui.Heading("About", level=1)
ui.Text("FluxUI is a reactive Python web UI framework.")
app.run(port=8000)
Path Parameters¶
Declare dynamic segments with {name} syntax. They are passed as keyword arguments
to the page function:
@app.page("/user/{id}")
def user_profile(session, id: str):
user = load_user(id)
if user is None:
ui.Alert(f"User {id!r} not found.", variant="danger")
return
ui.Heading(user.name, level=1)
ui.Text(user.email)
@app.page("/product/{category}/{slug}")
def product_detail(session, category: str, slug: str):
product = load_product(category, slug)
ui.Heading(product.title, level=1)
ui.Text(product.description)
Programmatic Navigation¶
Use session.navigate(url) from within any callback to change pages programmatically:
@app.page("/login")
def login(session):
username = ui.state("")
password = ui.state("")
error = ui.state("")
async def handle_login():
if authenticate(username.peek(), password.peek()):
await session.navigate("/dashboard")
else:
error.set("Invalid credentials")
with ui.Card(title="Sign in"):
ui.TextInput(label="Username", value=username, on_change=username.set)
ui.TextInput(label="Password", value=password, on_change=password.set)
if error.value:
ui.Alert(error, variant="danger")
ui.Button("Sign in", on_click=handle_login)
Replace history entry¶
Pass replace=True to replace the current history entry instead of pushing a new one.
The user's "back" button will skip the replaced page:
SPA Behaviour¶
- All navigation happens client-side — the browser never does a full page load after the initial shell.
- The URL in the address bar updates correctly via the History API.
- The browser "back" and "forward" buttons work as expected.
- Deep links work: opening
http://localhost:8000/user/42directly navigates to the/user/{id}page.
Accessing the Current Route¶
The current route is available on the session object:
@app.page("/dashboard")
def dashboard(session):
current = session.current_route # e.g. "/dashboard"
with ui.NavMenu(brand="MyApp"):
ui.NavItem("Home", href="/", active=lambda: session.current_route == "/")
ui.NavItem("Dashboard", href="/dashboard", active=lambda: session.current_route == "/dashboard")
404 Handling¶
If a route is not found, FluxUI renders a built-in 404 page. You can override it with a catch-all page:
@app.page("/404")
def not_found(session):
with ui.Column(align="center", justify="center"):
ui.Heading("404 — Page not found", level=1)
ui.Text("The page you are looking for does not exist.")
ui.Button("Go home", on_click=lambda: session.navigate("/"))
Note
Custom 404 routing via the FluxUI Router is planned for v0.2. For now,
handle unknown paths inside your page functions by checking parameters.
Per-Page Component Overrides¶
You can scope component overrides to a single page using the overrides= kwarg: