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

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, 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"
    }

@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),
    ]

While loading, a progress indicator is automatically displayed.

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, and any URL parameters
  • 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

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.1.tar.gz (10.6 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.1-py3-none-any.whl (8.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: flet_stack-0.2.1.tar.gz
  • Upload date:
  • Size: 10.6 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.1.tar.gz
Algorithm Hash digest
SHA256 1ea817645c30e9a8a9392f2846276af5618b6ecc8a6e4c3225fa10de1ef59f67
MD5 4558216347779f4a179a56246dadc728
BLAKE2b-256 72b325998420aed0d2feca6fb4384b4e64aebaec81bacd77636c6c9f5685f1e9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: flet_stack-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 8.9 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5715f124e9cdc3b4153a16df28f7ad05e2c4d42679f3ab260f6c02d99fa23bb9
MD5 913f265936999117133f1b62cdbe6636
BLAKE2b-256 dc4644b0632baaa6f39a3dbe35e42bbd911eae075e2664bfa644b4682f9f3834

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