Master-Detail

Responsive sidebar navigation pattern with master list and detail content area. On mobile devices, the sidebar is hidden in a drawer that can be toggled. On desktop (lg+ screens), the sidebar is always visible.

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


source

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


source

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


source

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


source

MasterDetail.get_item


def get_item(
    item_id:str, # Item identifier
)->Optional: # DetailItem or None

Get item by ID.

Context and Rendering Methods


source

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.


source

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.


source

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.


source

MasterDetail.render_detail


def render_detail(
    item:DetailItem, # Item to render
    ctx:InteractionContext, # Interaction context
)->FT: # Detail content

Render detail content for an item.


source

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


source

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

# 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)
# 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