# Example: Simple file browser with groups
from fasthtml.common import Div, H2, P, H3, Ul, Li
# Define render functions for each item
def render_file_overview(ctx: InteractionContext):
"""Render file details."""
file_data = ctx.get_data("file", {})
return Div(
H2(f"File: {file_data.get('name', 'Unknown')}"),
P(f"Size: {file_data.get('size', 0)} bytes"),
P(f"Modified: {file_data.get('modified', 'N/A')}")
)
def render_folder_overview(ctx: InteractionContext):
"""Render folder contents."""
folder_data = ctx.get_data("folder", {})
return Div(
H2(f"Folder: {folder_data.get('name', 'Unknown')}"),
P(f"Items: {folder_data.get('item_count', 0)}"),
H3("Contents:"),
Ul(*[Li(item) for item in folder_data.get('items', [])])
)
# Optional data loaders
def load_file_data(request):
"""Load file metadata."""
return {
"file": {
"name": "document.txt",
"size": 1024,
"modified": "2025-01-15"
}
}
def load_folder_data(request):
"""Load folder contents."""
return {
"folder": {
"name": "Documents",
"item_count": 3,
"items": ["file1.txt", "file2.pdf", "file3.doc"]
}
}
# Create the master-detail interface with groups
file_browser = MasterDetail(
interface_id="file_browser",
master_title="File Browser",
items=[
DetailItemGroup(
id="documents",
title="Documents",
items=[
DetailItem(
id="doc1",
label="document.txt",
render=render_file_overview,
data_loader=load_file_data,
badge_text="1KB",
badge_color=badge_colors.info
),
DetailItem(
id="doc2",
label="report.pdf",
render=render_file_overview,
badge_text="2KB",
badge_color=badge_colors.info
)
],
badge_text="2 files"
),
DetailItemGroup(
id="media",
title="Media",
items=[
DetailItem(
id="img1",
label="photo.jpg",
render=render_file_overview,
badge_text="512KB",
badge_color=badge_colors.warning
)
],
badge_text="1 file"
),
DetailItem(
id="root_folder",
label="All Files",
render=render_folder_overview,
data_loader=load_folder_data,
badge_text="3 items",
badge_color=badge_colors.success
)
]
)
# Generate router
browser_router = file_browser.create_router(prefix="/files")
# In your FastHTML app, register the router:
# from cjm_fasthtml_app_core.core.routing import register_routes
# register_routes(app, browser_router)
#
# Or directly:
# browser_router.to_app(app)Master-Detail
Detail Item Definition
The DetailItem class defines a single item in the master list. Each item has: - Unique identifier - Display label for the master list - Render function that generates the detail view UI - Optional badge text and color - Optional icon - Optional data loader for fetching required data
DetailItem
def DetailItem(
id:str, label:str, render:Callable, badge_text:Optional=None, badge_color:Optional=None, icon:Optional=None,
data_loader:Optional=None, load_on_demand:bool=True
)->None:
Definition of a single item in the master-detail pattern.
Detail Item Group Definition
The DetailItemGroup class groups related items in a collapsible section. Each group has: - Unique identifier - Display title - List of items in the group - Collapsible state control - Optional icon
DetailItemGroup
def DetailItemGroup(
id:str, title:str, items:List, default_open:bool=True, icon:Optional=None, badge_text:Optional=None,
badge_color:Optional=None
)->None:
Group of related detail items in a collapsible section.
MasterDetail Class
The MasterDetail class manages a responsive master-detail interface. It: - Renders master list (sidebar) with items and optional groups - Manages active item selection - Renders detail content for selected item - Supports badges and status indicators - Supports hierarchical grouping with collapsible sections - Responsive design: Drawer toggleable on mobile, always visible on desktop (lg+) - Mobile-friendly: Includes hamburger menu button for navigation - Generates routes automatically - Provides OOB updates for coordinated UI changes
MasterDetail
def MasterDetail(
interface_id:str, # Unique identifier for this interface
items:List, # List of items/groups
default_item:Optional=None, # Default item ID (defaults to first item)
container_id:str='master-detail-container', # HTML ID for container
master_id:str='master-detail-master', # HTML ID for master list
detail_id:str='master-detail-detail', # HTML ID for detail area
master_width:str='w-64', # Tailwind width class for master list
master_title:Optional=None, # Optional title for master list
show_on_htmx_only:bool=False, # Whether to show full interface for non-HTMX requests
):
Manage master-detail interfaces with sidebar navigation and detail content area.
Item Management Methods
MasterDetail.get_item
def get_item(
item_id:str, # Item identifier
)->Optional: # DetailItem or None
Get item by ID.
Context and Rendering Methods
MasterDetail.create_context
def create_context(
request:Any, # FastHTML request object
sess:Any, # FastHTML session object
item:DetailItem, # Current item
)->InteractionContext: # Interaction context for rendering
Create interaction context for an item.
MasterDetail.render_master
def render_master(
active_item_id:str, # Currently active item ID
item_route_func:Callable, # Function to generate item route
include_wrapper:bool=True, # Whether to include outer wrapper div
)->FT: # Master list element
Render master list (sidebar) with items and groups.
MasterDetail.render_master_oob
def render_master_oob(
active_item_id:str, # Currently active item ID
item_route_func:Callable, # Function to generate item route
)->FT: # Master list with OOB swap attribute
Render master list with OOB swap attribute for coordinated updates.
MasterDetail.render_detail
def render_detail(
item:DetailItem, # Item to render
ctx:InteractionContext, # Interaction context
)->FT: # Detail content
Render detail content for an item.
MasterDetail.render_full_interface
def render_full_interface(
active_item_id:str, # Currently active item ID
item_route_func:Callable, # Function to generate item route
request:Any, # FastHTML request object
sess:Any, # FastHTML session object
)->FT: # Complete master-detail interface
Render complete responsive master-detail interface with drawer for mobile.
Route Generation
MasterDetail.create_router
def create_router(
prefix:str='', # URL prefix for routes (e.g., "/media")
)->APIRouter: # APIRouter with generated routes
Create FastHTML router with generated routes for this master-detail interface.
Usage Example
Here’s a complete example showing how to create a master-detail interface:
Note: The interface is automatically responsive: - Mobile (< lg): Master list hidden in a drawer with hamburger menu toggle - Desktop (≥ lg): Master list always visible as a sidebar
# Test master-detail structure
print(f"Interface has {len(file_browser.item_index)} items")
print(f"Default item: {file_browser.default_item}")
print(f"Item IDs: {list(file_browser.item_index.keys())}")
print(f"Master width: {file_browser.master_width}")Interface has 4 items
Default item: doc1
Item IDs: ['doc1', 'doc2', 'img1', 'root_folder']
Master width: w-64