Skip to main content

Decorator-based routing with view stacking for Flet applications

Project description

flet-stack

Component-based routing with automatic view stacking for Flet applications.

PyPI version Python versions PyPI Downloads

Features

  • 🎯 Decorator-based routing - Clean, intuitive @view() decorator for route definitions
  • 🔄 Observable state management - Built-in state management using @ft.observable dataclasses
  • Async support - Handle async data loading with automatic loading indicators
  • 🎨 URL parameters - Extract parameters from routes like /user/{id}
  • 🧩 Component-based architecture - Uses Flet's modern @ft.component pattern
  • 🚀 Simple setup - Just call page.render_views(FletStack) in your app
  • 🔐 Custom initial routes - Start your app at any route

Requirements

  • Python 3.9+
  • Flet >= 0.70.0.dev6281

Installation

From PyPI

pip install flet-stack

From GitHub

pip install git+https://github.com/fasilwdr/flet-stack.git

Install Specific Version

pip install git+https://github.com/fasilwdr/flet-stack.git@v0.2.3

From Source

git clone https://github.com/fasilwdr/flet-stack.git
cd flet-stack
pip install .

Quick Start

import flet as ft
from flet_stack import view, FletStack
import asyncio

# Define your routes with the @view decorator
@view("/")
@ft.component
def home_view():
    return [
        ft.Text("Home Page", size=30),
        ft.Button(
            "Go to Profile",
            on_click=lambda _: asyncio.create_task(
                ft.context.page.push_route("/profile")
            )
        ),
    ]

@view("/profile", appbar=ft.AppBar())
@ft.component
def profile_view():
    return [
        ft.Text("Profile Page", size=30),
    ]

# Run your app
ft.run(lambda page: page.render_views(FletStack))

That's it! The routing is automatically handled by FletStack.

Advanced Usage

URL Parameters

Extract parameters from your routes:

@view("/user/{user_id}")
@ft.component
def user_view(user_id):
    return [
        ft.Text(f"User Profile: {user_id}", size=30),
    ]

State Management

Use observable dataclasses to manage component state:

from dataclasses import dataclass

@ft.observable
@dataclass
class CounterState:
    count: int = 0
    
    def increment(self, e):
        self.count += 1
    
    def decrement(self, e):
        self.count -= 1

@view("/counter", state_class=CounterState, appbar=ft.AppBar())
@ft.component
def counter_view(state):
    return [
        ft.Text(f"Count: {state.count}", size=30),
        ft.Row([
            ft.Button("Decrement", on_click=state.decrement),
            ft.Button("Increment", on_click=state.increment),
        ]),
    ]

Async Data Loading

Load data asynchronously before showing your view:

@ft.observable
@dataclass
class UserState:
    user_data: dict = None

async def load_user_data(state, view, user_id):
    # Simulate API call
    await asyncio.sleep(1)
    state.user_data = {
        "id": user_id,
        "name": f"User {user_id}",
        "email": f"user{user_id}@example.com"
    }
    # Update the appbar title dynamically
    view.appbar = ft.AppBar(title=ft.Text(state.user_data['name']))

@view("/user/{user_id}", state_class=UserState, on_load=load_user_data)
@ft.component
def user_detail_view(state, user_id):    
    return [
        ft.Text(f"Name: {state.user_data['name']}", size=20),
        ft.Text(f"Email: {state.user_data['email']}", size=16),
        ft.Text(f"ID: {state.user_data['id']}", size=16),
    ]

The view parameter in on_load allows you to update any view property dynamically, including appbar, bgcolor, padding, and more.

Sync Data Loading

You can also use synchronous loading functions:

def load_item_info(state, category, item_id, page):
    """Sync data loading with access to page object"""
    state.info = {
        "category": category.capitalize(),
        "item_id": item_id,
        "name": f"{category.capitalize()} Item #{item_id}",
        "price": f"${int(item_id) * 10}.99"
    }

@view(
    "/category/{category}/item/{item_id}",
    state_class=ItemState,
    on_load=load_item_info
)
@ft.component
def item_view(state, category, item_id):
    return [
        ft.Text(f"{state.info['name']}", size=20),
        ft.Text(f"Price: {state.info['price']}", size=18),
    ]

View Configuration

Pass additional Flet view properties:

@view(
    "/settings",
    appbar=ft.AppBar(title=ft.Text("Settings")),
    bgcolor=ft.Colors.BLUE_GREY_50,
    padding=20,
    horizontal_alignment=ft.CrossAxisAlignment.CENTER,
    vertical_alignment=ft.MainAxisAlignment.CENTER,
)
@ft.component
def settings_view():
    return [ft.Text("Settings", size=30)]

Multiple URL Parameters

Handle routes with multiple parameters:

@view("/category/{category}/item/{item_id}")
@ft.component
def item_view(category, item_id):
    return [
        ft.Text(f"Category: {category}", size=20),
        ft.Text(f"Item ID: {item_id}", size=20),
    ]

Setting Initial Route

You can start your app at any route instead of the default /:

def main(page: ft.Page):
    page.title = "My App"
    page.route = "/login"  # Start at login page
    page.render_views(FletStack)

ft.run(main)

API Reference

@view Decorator

@view(route: str, state_class: Type = None, on_load: Optional[Callable] = None, **view_kwargs)
  • route: The route path for this view (e.g., /, /user/{user_id})
  • state_class: Optional dataclass decorated with @ft.observable for state management
  • on_load: Optional function to call before rendering (can be async)
    • Can accept parameters: state, page, view, and any URL parameters
    • The view parameter is a proxy object that allows updating view properties
  • view_kwargs: Additional kwargs passed to ft.View (e.g., appbar, bgcolor, padding)

FletStack Component

Main component that manages the routing stack and renders views.

# Option 1: Direct render
ft.run(lambda page: page.render_views(FletStack))

# Option 2: In main function
def main(page: ft.Page):
    page.title = "My App"
    page.route = "/login"  # Optional: Set initial route
    page.render_views(FletStack)

ft.run(main)

Navigation

Use asyncio.create_task with ft.context.page.push_route:

# Navigate to a route
asyncio.create_task(ft.context.page.push_route("/profile"))

# In button click handler
ft.Button(
    "Go to Profile",
    on_click=lambda _: asyncio.create_task(
        ft.context.page.push_route("/profile")
    )
)

Examples

Check the examples/ directory for more detailed examples:

  • basic_example.py - Simple routing and navigation
  • advanced_example.py - State management, async loading, and URL parameters

How It Works

flet-stack provides a FletStack component that:

  1. Registers all @view decorated functions
  2. Manages a navigation stack for route changes
  3. Handles state management with observable dataclasses
  4. Manages async/sync loading with automatic progress indicators
  5. Renders views with proper navigation support
  6. Supports custom initial routes via page.route
  7. Allows dynamic property updates via the state, page, view parameter in on_load

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Built on top of the amazing Flet framework by Feodor Fitsner.

Support

If you encounter any issues or have questions:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flet_stack-0.2.3.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flet_stack-0.2.3-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file flet_stack-0.2.3.tar.gz.

File metadata

  • Download URL: flet_stack-0.2.3.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for flet_stack-0.2.3.tar.gz
Algorithm Hash digest
SHA256 a436a152ebf5efaa559871d17396c71baedd67a986dca5b52dcc1d34f7954058
MD5 dfc5cbc06db07f8266bffea80f80617c
BLAKE2b-256 113ea22f3005012846785898431cf0c36ac9bc8f201c4989b72956ea88b2dc8a

See more details on using hashes here.

File details

Details for the file flet_stack-0.2.3-py3-none-any.whl.

File metadata

  • Download URL: flet_stack-0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for flet_stack-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e07b90f2b6f433f4d086a4abe49a63008c4e6e3617097e76e48458bd3e7f915b
MD5 cdaf5b750a1b57b7ddec7b0678bd6c3a
BLAKE2b-256 2434923b71c3cd41aac2fb5116a801234b6b356721c3bcd20afb0ef8eb04f107

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page