cjm-fasthtml-interactions
Install
pip install cjm_fasthtml_interactionsProject Structure
nbs/
├── core/ (3)
│ ├── context.ipynb # Context management for interaction patterns providing access to state, request, and custom data
│ ├── html_ids.ipynb # Centralized HTML ID constants for interaction pattern components
│ └── state_store.ipynb # Server-side workflow state storage implementations
└── patterns/ (7)
├── async_loading.ipynb # Pattern for asynchronous content loading with skeleton loaders and loading indicators
├── master_detail.ipynb # 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.
├── modal_dialog.ipynb # Pattern for modal dialogs with customizable content, sizes, and actions
├── pagination.ipynb # Pagination pattern with automatic route generation and state management
├── sse_connection_monitor.ipynb # Pattern for monitoring Server-Sent Events (SSE) connections with visual status indicators and automatic reconnection
├── step_flow.ipynb # Multi-step wizard pattern with state management, navigation, and route generation
└── tabbed_interface.ipynb # Multi-tab interface pattern with automatic routing, state management, and DaisyUI styling
Total: 10 notebooks across 2 directories
Module Dependencies
graph LR
core_context[core.context<br/>Interaction Context]
core_html_ids[core.html_ids<br/>HTML IDs]
core_state_store[core.state_store<br/>Workflow State Store]
patterns_async_loading[patterns.async_loading<br/>Async Loading Container]
patterns_master_detail[patterns.master_detail<br/>Master-Detail]
patterns_modal_dialog[patterns.modal_dialog<br/>Modal Dialog]
patterns_pagination[patterns.pagination<br/>Pagination]
patterns_sse_connection_monitor[patterns.sse_connection_monitor<br/>SSE Connection Monitor]
patterns_step_flow[patterns.step_flow<br/>Step Flow]
patterns_tabbed_interface[patterns.tabbed_interface<br/>Tabbed Interface]
patterns_master_detail --> core_html_ids
patterns_master_detail --> core_context
patterns_modal_dialog --> core_html_ids
patterns_modal_dialog --> patterns_async_loading
patterns_pagination --> core_html_ids
patterns_sse_connection_monitor --> core_html_ids
patterns_step_flow --> core_state_store
patterns_step_flow --> core_html_ids
patterns_step_flow --> core_context
patterns_tabbed_interface --> core_html_ids
patterns_tabbed_interface --> core_context
11 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
Async Loading Container (async_loading.ipynb)
Pattern for asynchronous content loading with skeleton loaders and loading indicators
Import
from cjm_fasthtml_interactions.patterns.async_loading import (
LoadingType,
AsyncLoadingContainer
)Functions
def AsyncLoadingContainer(
container_id: str, # HTML ID for the container
load_url: str, # URL to fetch content from
loading_type: LoadingType = LoadingType.SPINNER, # Type of loading indicator
loading_size: str = "lg", # Size of loading indicator (xs, sm, md, lg)
loading_message: Optional[str] = None, # Optional message to display while loading
skeleton_content: Optional[Any] = None, # Optional skeleton/placeholder content
trigger: str = "load", # HTMX trigger event (default: load on page load)
swap: str = "outerHTML", # HTMX swap method (default: replace entire container)
container_cls: Optional[str] = None, # Additional CSS classes for container
**kwargs # Additional attributes for the container
) -> FT: # Div element with async loading configured
"Create a container that asynchronously loads content from a URL."Classes
class LoadingType(Enum):
"Types of loading indicators for async content."Interaction Context (context.ipynb)
Context management for interaction patterns providing access to state, request, and custom data
Import
from cjm_fasthtml_interactions.core.context import (
InteractionContext
)Classes
@dataclass
class InteractionContext:
"Context for interaction patterns providing access to state, request, and custom data."
state: Dict[str, Any] = field(...) # Workflow state
request: Optional[Any] # FastHTML request object
session: Optional[Any] # FastHTML session object
data: Dict[str, Any] = field(...) # Custom data from data loaders
metadata: Dict[str, Any] = field(...) # Additional metadata
def get(self,
key: str, # Key to retrieve from state
default: Any = None # Default value if key not found
) -> Any: # Value from state or default
"Get value from workflow state."
def get_data(self,
key: str, # Key to retrieve from data
default: Any = None # Default value if key not found
) -> Any: # Value from data or default
"Get value from custom data."
def has(self,
key: str # Key to check in state
) -> bool: # True if key exists in state
"Check if key exists in workflow state."
def set(self,
key: str, # Key to set in state
value: Any # Value to store
) -> None
"Set value in workflow state."
def get_all_state(self) -> Dict[str, Any]: # All workflow state
"""Get all workflow state as dictionary."""
return self.state.copy()
def update_state(self,
updates: Dict[str, Any] # State updates to apply
) -> None
"Get all workflow state as dictionary."
def update_state(self,
updates: Dict[str, Any] # State updates to apply
) -> None
"Update multiple state values at once."HTML IDs (html_ids.ipynb)
Centralized HTML ID constants for interaction pattern components
Import
from cjm_fasthtml_interactions.core.html_ids import (
InteractionHtmlIds
)Classes
class InteractionHtmlIds(AppHtmlIds):
"""
HTML ID constants for interaction pattern components.
Inherits from AppHtmlIds:
- MAIN_CONTENT = "main-content"
- ALERT_CONTAINER = "alert-container"
- as_selector(id_str) - static method
"""
def step_content(step_id: str # Step identifier
) -> str: # HTML ID for step content
"Generate HTML ID for a specific step's content."
def step_indicator(step_id: str # Step identifier
) -> str: # HTML ID for step indicator
"Generate HTML ID for a specific step's progress indicator."
def tab_radio(tab_id: str # Tab identifier
) -> str: # HTML ID for tab radio input
"Generate HTML ID for a specific tab's radio input."
def tab_content(tab_id: str # Tab identifier
) -> str: # HTML ID for tab content
"Generate HTML ID for a specific tab's content."
def master_item(item_id: str # Item identifier
) -> str: # HTML ID for master list item
"Generate HTML ID for a master list item."
def master_group(group_id: str # Group identifier
) -> str: # HTML ID for master list group
"Generate HTML ID for master list group."
def detail_content(item_id: str # Item identifier
) -> str: # HTML ID for detail content
"Generate HTML ID for detail content area."
def modal_dialog(modal_id: str # Modal identifier
) -> str: # HTML ID for modal dialog
"Generate HTML ID for a modal dialog."
def modal_dialog_content(modal_id: str # Modal identifier
) -> str: # HTML ID for modal content area
"Generate HTML ID for modal content area."
def sse_status(connection_id: str # SSE connection identifier
) -> str: # HTML ID for SSE status indicator
"Generate HTML ID for SSE connection status indicator."
def sse_element(connection_id: str # SSE connection identifier
) -> str: # HTML ID for SSE connection element
"Generate HTML ID for SSE connection element."
def pagination_container(pagination_id: str # Pagination identifier
) -> str: # HTML ID for pagination container
"Generate HTML ID for pagination container (entire paginated view)."
def pagination_content(pagination_id: str # Pagination identifier
) -> str: # HTML ID for pagination content area
"Generate HTML ID for pagination content area (items display)."
def pagination_nav(pagination_id: str # Pagination identifier
) -> str: # HTML ID for pagination navigation controls
"Generate HTML ID for pagination navigation controls."Master-Detail (master_detail.ipynb)
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.
Import
from cjm_fasthtml_interactions.patterns.master_detail import (
DetailItem,
DetailItemGroup,
MasterDetail
)Functions
@patch
def get_item(self:MasterDetail,
item_id: str # Item identifier
) -> Optional[DetailItem]: # DetailItem or None
"Get item by ID."@patch
def create_context(self:MasterDetail,
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."@patch
def render_master(self:MasterDetail,
active_item_id: str, # Currently active item ID
item_route_func: Callable[[str], str], # 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."@patch
def _render_menu_items(self:MasterDetail,
active_item_id: str, # Currently active item ID
item_route_func: Callable[[str], str] # Function to generate item route
) -> List[FT]: # List of menu item elements
"Render menu items and groups (internal helper)."@patch
def render_master_oob(self:MasterDetail,
active_item_id: str, # Currently active item ID
item_route_func: Callable[[str], str] # Function to generate item route
) -> FT: # Master list with OOB swap attribute
"Render master list with OOB swap attribute for coordinated updates."@patch
def render_detail(self:MasterDetail,
item: DetailItem, # Item to render
ctx: InteractionContext # Interaction context
) -> FT: # Detail content
"Render detail content for an item."@patch
def render_full_interface(self:MasterDetail,
active_item_id: str, # Currently active item ID
item_route_func: Callable[[str], str], # 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."@patch
def create_router(self:MasterDetail,
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."Classes
@dataclass
class DetailItem:
"Definition of a single item in the master-detail pattern."
id: str # Unique identifier
label: str # Display text in master list
render: Callable[[InteractionContext], Any] # Function to render detail view
badge_text: Optional[str] # Optional badge text (e.g., "configured", "3 items")
badge_color: Optional[str] # Badge color class (e.g., badge_colors.success)
icon: Optional[Any] # Optional icon element
data_loader: Optional[Callable[[Any], Dict[str, Any]]] # Data loading function
load_on_demand: bool = True # Whether to load content only when item is selected@dataclass
class DetailItemGroup:
"Group of related detail items in a collapsible section."
id: str # Group identifier
title: str # Group display title
items: List[DetailItem] # Items in this group
default_open: bool = True # Whether group is expanded by default
icon: Optional[Any] # Optional group icon
badge_text: Optional[str] # Optional badge for the group
badge_color: Optional[str] # Badge color for the groupclass MasterDetail:
def __init__(
self,
interface_id: str, # Unique identifier for this interface
items: List[Union[DetailItem, DetailItemGroup]], # List of items/groups
default_item: Optional[str] = None, # Default item ID (defaults to first item)
container_id: str = InteractionHtmlIds.MASTER_DETAIL_CONTAINER, # HTML ID for container
master_id: str = InteractionHtmlIds.MASTER_DETAIL_MASTER, # HTML ID for master list
detail_id: str = InteractionHtmlIds.MASTER_DETAIL_DETAIL, # HTML ID for detail area
master_width: str = "w-64", # Tailwind width class for master list
master_title: Optional[str] = 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."
def __init__(
self,
interface_id: str, # Unique identifier for this interface
items: List[Union[DetailItem, DetailItemGroup]], # List of items/groups
default_item: Optional[str] = None, # Default item ID (defaults to first item)
container_id: str = InteractionHtmlIds.MASTER_DETAIL_CONTAINER, # HTML ID for container
master_id: str = InteractionHtmlIds.MASTER_DETAIL_MASTER, # HTML ID for master list
detail_id: str = InteractionHtmlIds.MASTER_DETAIL_DETAIL, # HTML ID for detail area
master_width: str = "w-64", # Tailwind width class for master list
master_title: Optional[str] = None, # Optional title for master list
show_on_htmx_only: bool = False # Whether to show full interface for non-HTMX requests
)
"Initialize master-detail manager."Modal Dialog (modal_dialog.ipynb)
Pattern for modal dialogs with customizable content, sizes, and actions
Import
from cjm_fasthtml_interactions.patterns.modal_dialog import (
ModalSize,
ModalDialog,
ModalTriggerButton
)Functions
def ModalDialog(
modal_id: str, # Unique identifier for the modal
content: Any, # Content to display in the modal
size: Union[ModalSize, str] = ModalSize.MEDIUM, # Size preset or custom size
show_close_button: bool = True, # Whether to show X close button in top-right
close_on_backdrop: bool = True, # Whether clicking backdrop closes modal
auto_show: bool = False, # Whether to show modal immediately on render
content_id: Optional[str] = None, # Optional ID for content area (for HTMX targeting)
custom_width: Optional[str] = None, # Custom width class (e.g., "w-96")
custom_height: Optional[str] = None, # Custom height class (e.g., "h-screen")
box_cls: Optional[str] = None, # Additional classes for modal box
**kwargs # Additional attributes for the dialog element
) -> FT: # Dialog element with modal dialog configured
"Create a modal dialog using native HTML dialog element with DaisyUI styling."def ModalTriggerButton(
modal_id: str, # ID of the modal to trigger
label: str, # Button label text
button_cls: Optional[str] = None, # Additional button classes
**kwargs # Additional button attributes
) -> FT: # Button element that triggers modal
"Create a button that opens a modal dialog."Classes
class ModalSize(Enum):
"Predefined size options for modal dialogs."Pagination (pagination.ipynb)
Pagination pattern with automatic route generation and state management
Import
from cjm_fasthtml_interactions.patterns.pagination import (
PaginationStyle,
Pagination
)Functions
@patch
def get_total_pages(self:Pagination,
total_items: int # Total number of items
) -> int: # Total number of pages
"Calculate total number of pages."@patch
def get_page_items(self:Pagination,
all_items: List[Any], # All items
page: int # Current page number (1-indexed)
) -> tuple: # (page_items, start_idx, end_idx)
"Get items for the current page."@patch
def build_route(self:Pagination,
page: int, # Page number
request: Any, # FastHTML request object
page_route_func: Callable # Route function from create_router
) -> str: # Complete route with preserved params
"Build route URL with preserved query parameters."@patch
def render_navigation_controls(self:Pagination,
current_page: int, # Current page number
total_pages: int, # Total number of pages
route_func: Callable[[int], str] # Function to generate route for page
) -> FT: # Navigation controls element
"Render pagination navigation controls."@patch
def render_page_content(self:Pagination,
page_items: List[Any], # Items for current page
current_page: int, # Current page number
total_pages: int, # Total number of pages
request: Any, # FastHTML request object
route_func: Callable[[int], str] # Function to generate route for page
) -> FT: # Complete page content with items and navigation
"Render complete page content with items and pagination controls."@patch
def create_router(self:Pagination,
prefix: str = "" # URL prefix for routes (e.g., "/library")
) -> APIRouter: # APIRouter with generated routes
"Create FastHTML router with generated routes for pagination."Classes
class PaginationStyle(Enum):
"Display styles for pagination controls."class Pagination:
def __init__(
self,
pagination_id: str, # Unique identifier for this pagination instance
data_loader: Callable[[Any], List[Any]], # Function that returns all items
render_items: Callable[[List[Any], int, Any], Any], # Function to render items for a page
items_per_page: int = 20, # Number of items per page
container_id: str = None, # HTML ID for container (auto-generated if None)
content_id: str = None, # HTML ID for content area (auto-generated if None)
preserve_params: List[str] = None, # Query parameters to preserve
style: PaginationStyle = PaginationStyle.SIMPLE, # Pagination display style
prev_text: str = "« Previous", # Text for previous button
next_text: str = "Next »", # Text for next button
page_info_format: str = "Page {current} of {total}", # Format for page info
button_size: str = None, # Button size class
push_url: bool = True, # Whether to update URL with hx-push-url
show_endpoints: bool = False, # Whether to show First/Last buttons
first_text: str = "«« First", # Text for first page button
last_text: str = "Last »»", # Text for last page button
redirect_route: Optional[Callable[[int, Dict[str, Any]], str]] = None, # Route to redirect non-HTMX requests
)
"Manage paginated views with automatic route generation and state management."
def __init__(
self,
pagination_id: str, # Unique identifier for this pagination instance
data_loader: Callable[[Any], List[Any]], # Function that returns all items
render_items: Callable[[List[Any], int, Any], Any], # Function to render items for a page
items_per_page: int = 20, # Number of items per page
container_id: str = None, # HTML ID for container (auto-generated if None)
content_id: str = None, # HTML ID for content area (auto-generated if None)
preserve_params: List[str] = None, # Query parameters to preserve
style: PaginationStyle = PaginationStyle.SIMPLE, # Pagination display style
prev_text: str = "« Previous", # Text for previous button
next_text: str = "Next »", # Text for next button
page_info_format: str = "Page {current} of {total}", # Format for page info
button_size: str = None, # Button size class
push_url: bool = True, # Whether to update URL with hx-push-url
show_endpoints: bool = False, # Whether to show First/Last buttons
first_text: str = "«« First", # Text for first page button
last_text: str = "Last »»", # Text for last page button
redirect_route: Optional[Callable[[int, Dict[str, Any]], str]] = None, # Route to redirect non-HTMX requests
)
"Initialize pagination manager."SSE Connection Monitor (sse_connection_monitor.ipynb)
Pattern for monitoring Server-Sent Events (SSE) connections with visual status indicators and automatic reconnection
Import
from cjm_fasthtml_interactions.patterns.sse_connection_monitor import (
SSEConnectionConfig,
create_connection_status_indicators,
SSEConnectionMonitorScript,
SSEConnectionMonitor
)Functions
def create_connection_status_indicators(
status_size: str = "sm", # Size of status indicator dot (xs, sm, md, lg)
show_text: bool = True, # Whether to show status text
text_size: str = "text-sm", # Text size class
hide_text_on_mobile: bool = True # Hide text on small screens
) -> Dict[str, FT]: # Dictionary of status state to indicator element
"Create status indicator elements for different connection states."def SSEConnectionMonitorScript(
connection_id: str, # Unique identifier for this SSE connection
status_indicators: Dict[str, FT], # Status indicator elements for each state
config: Optional[SSEConnectionConfig] = None # Configuration options
) -> FT: # Script element with monitoring code
"Create a script that monitors SSE connection status and manages reconnection."def SSEConnectionMonitor(
connection_id: str, # Unique identifier for this SSE connection
status_size: str = "sm", # Size of status indicator
show_text: bool = True, # Whether to show status text
hide_text_on_mobile: bool = True, # Hide text on small screens
config: Optional[SSEConnectionConfig] = None, # Configuration options
container_cls: Optional[str] = None # Additional CSS classes for status container
) -> tuple[FT, FT]: # Tuple of (status_container, monitor_script)
"Create a complete SSE connection monitoring system."Classes
@dataclass
class SSEConnectionConfig:
"Configuration for SSE connection monitoring."
max_reconnect_attempts: int = 10 # Maximum number of reconnection attempts
reconnect_delay: int = 1000 # Initial reconnect delay in milliseconds
max_backoff_multiplier: int = 5 # Maximum backoff multiplier for reconnect delay
monitor_visibility: bool = True # Monitor tab visibility and reconnect when visible
log_to_console: bool = True # Enable console logging for debuggingWorkflow State Store (state_store.ipynb)
Server-side workflow state storage implementations
Import
from cjm_fasthtml_interactions.core.state_store import (
WorkflowStateStore,
get_session_id,
InMemoryWorkflowStateStore
)Functions
def get_session_id(
sess: Any, # FastHTML session object
key: str = "_workflow_session_id" # Session key for storing the ID
) -> str: # Stable session identifier
"Get or create a stable session identifier."Classes
@runtime_checkable
class WorkflowStateStore(Protocol):
"Protocol for workflow state storage backends."
def get_current_step(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> Optional[str]: # Current step ID or None
"Get current step ID for a workflow."
def set_current_step(self,
flow_id: str, # Workflow identifier
sess: Any, # FastHTML session object
step_id: str # Step ID to set as current
) -> None
"Set current step ID for a workflow."
def get_state(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> Dict[str, Any]: # Workflow state dictionary
"Get all workflow state."
def update_state(self,
flow_id: str, # Workflow identifier
sess: Any, # FastHTML session object
updates: Dict[str, Any] # State updates to apply
) -> None
"Update workflow state with new values."
def clear_state(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> None
"Clear all workflow state."class InMemoryWorkflowStateStore:
def __init__(self):
"""Initialize empty state storage."""
self._current_steps: Dict[str, str] = {} # {flow_id:session_id -> step_id}
"In-memory workflow state storage for development and testing."
def __init__(self):
"""Initialize empty state storage."""
self._current_steps: Dict[str, str] = {} # {flow_id:session_id -> step_id}
"Initialize empty state storage."
def get_current_step(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> Optional[str]: # Current step ID or None
"Get current step ID for a workflow."
def set_current_step(self,
flow_id: str, # Workflow identifier
sess: Any, # FastHTML session object
step_id: str # Step ID to set as current
) -> None
"Set current step ID for a workflow."
def get_state(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> Dict[str, Any]: # Workflow state dictionary
"Get all workflow state."
def update_state(self,
flow_id: str, # Workflow identifier
sess: Any, # FastHTML session object
updates: Dict[str, Any] # State updates to apply
) -> None
"Update workflow state with new values."
def clear_state(self,
flow_id: str, # Workflow identifier
sess: Any # FastHTML session object
) -> None
"Clear all workflow state."Step Flow (step_flow.ipynb)
Multi-step wizard pattern with state management, navigation, and route generation
Import
from cjm_fasthtml_interactions.patterns.step_flow import (
Step,
StepFlow
)Functions
@patch
def get_step(self:StepFlow,
step_id: str # Step identifier
) -> Optional[Step]: # Step object or None
"Get step by ID."@patch
def get_step_index(self:StepFlow,
step_id: str # Step identifier
) -> Optional[int]: # Step index or None
"Get step index by ID."@patch
def get_current_step_id(self:StepFlow,
sess: Any # FastHTML session object
) -> str: # Current step ID
"Get current step ID from state store."@patch
def set_current_step(self:StepFlow,
sess: Any, # FastHTML session object
step_id: str # Step ID to set as current
) -> None
"Set current step in state store."@patch
def get_next_step_id(self:StepFlow,
current_step_id: str # Current step ID
) -> Optional[str]: # Next step ID or None if last step
"Get the ID of the next step."@patch
def get_previous_step_id(self:StepFlow,
current_step_id: str # Current step ID
) -> Optional[str]: # Previous step ID or None if first step
"Get the ID of the previous step."@patch
def is_last_step(self:StepFlow,
step_id: str # Step ID to check
) -> bool: # True if this is the last step
"Check if step is the last step."@patch
def is_first_step(self:StepFlow,
step_id: str # Step ID to check
) -> bool: # True if this is the first step
"Check if step is the first step."@patch
def get_workflow_state(self:StepFlow,
sess: Any # FastHTML session object
) -> Dict[str, Any]: # All workflow state
"Get all workflow state from state store."@patch
def update_workflow_state(self:StepFlow,
sess: Any, # FastHTML session object
updates: Dict[str, Any] # State updates
) -> None
"Update workflow state with new values."@patch
def clear_workflow(self:StepFlow,
sess: Any # FastHTML session object
) -> None
"Clear all workflow state."@patch
def _summarize_state(self:StepFlow,
state: Dict[str, Any] # State dictionary to summarize
) -> str: # Human-readable summary string
"Create a concise summary of state for debug output."@patch
def create_context(self:StepFlow,
request: Any, # FastHTML request object
sess: Any, # FastHTML session object
step: Step # Current step
) -> InteractionContext: # Interaction context for rendering
"Create interaction context for a step."@patch
def render_progress(self:StepFlow,
sess: Any # FastHTML session object
) -> FT: # Progress indicator or empty Div
"Render progress indicator showing all steps."@patch
def render_step_content(self:StepFlow,
step_obj: Step, # Step to render
ctx: InteractionContext, # Interaction context
next_route: str, # Route for next/submit
back_route: Optional[str] = None, # Route for back
cancel_route: Optional[str] = None # Route for cancel
) -> FT: # Complete step content with optional progress and navigation
"Render step content with optional progress indicator and navigation."@patch
def render_navigation(self:StepFlow,
step_id: str, # Current step ID
next_route: str, # Route for next/submit action
back_route: Optional[str] = None, # Route for back action
cancel_route: Optional[str] = None, # Route for cancel action
) -> FT: # Navigation button container
"Render navigation buttons for a step."@patch
def create_router(self:StepFlow,
prefix: str = "" # URL prefix for routes (e.g., "/transcription")
) -> APIRouter: # APIRouter with generated routes
"Create FastHTML router with generated routes for this flow."Classes
@dataclass
class Step:
"Definition of a single step in a multi-step workflow."
id: str # Unique step identifier (used in URLs)
title: str # Display title for the step
render: Callable[[InteractionContext], Any] # Function to render step UI
validate: Optional[Callable[[Dict[str, Any]], bool]] # Validation function
data_loader: Optional[Callable[[Any], Dict[str, Any]]] # Data loading function
data_keys: List[str] = field(...) # State keys managed by this step
can_skip: bool = False # Whether this step can be skipped
show_back: bool = True # Whether to show back button
show_cancel: bool = True # Whether to show cancel button
next_button_text: str = 'Continue' # Text for next/submit button
on_enter: Optional[Callable[[Dict[str, Any], Any, Any], Any]] # Called when entering step, before render (state, request, sess) -> None or component
on_leave: Optional[Callable[[Dict[str, Any], Any, Any], Any]] # Called after validation, before navigation (state, request, sess) -> None or component
def is_valid(self, state: Dict[str, Any] # Current workflow state
) -> bool: # True if step is complete and valid
"Check if step has valid data in state."class StepFlow:
def __init__(
self,
flow_id: str, # Unique identifier for this workflow
steps: List[Step], # List of step definitions
state_store: Optional[WorkflowStateStore] = None, # Storage backend (defaults to InMemoryWorkflowStateStore)
container_id: str = InteractionHtmlIds.STEP_FLOW_CONTAINER, # HTML ID for content container
on_complete: Optional[Callable[[Dict[str, Any], Any], Any]] = None, # Completion handler
show_progress: bool = False, # Whether to show progress indicator
wrap_in_form: bool = True, # Whether to wrap content + navigation in a form
debug: bool = False # Whether to print debug information
)
"Manage multi-step workflows with automatic route generation and state management."
def __init__(
self,
flow_id: str, # Unique identifier for this workflow
steps: List[Step], # List of step definitions
state_store: Optional[WorkflowStateStore] = None, # Storage backend (defaults to InMemoryWorkflowStateStore)
container_id: str = InteractionHtmlIds.STEP_FLOW_CONTAINER, # HTML ID for content container
on_complete: Optional[Callable[[Dict[str, Any], Any], Any]] = None, # Completion handler
show_progress: bool = False, # Whether to show progress indicator
wrap_in_form: bool = True, # Whether to wrap content + navigation in a form
debug: bool = False # Whether to print debug information
)
"Initialize step flow manager."Tabbed Interface (tabbed_interface.ipynb)
Multi-tab interface pattern with automatic routing, state management, and DaisyUI styling
Import
from cjm_fasthtml_interactions.patterns.tabbed_interface import (
Tab,
TabbedInterface
)Functions
@patch
def get_tab(self:TabbedInterface,
tab_id: str # Tab identifier
) -> Optional[Tab]: # Tab object or None
"Get tab by ID."@patch
def get_tab_index(self:TabbedInterface,
tab_id: str # Tab identifier
) -> Optional[int]: # Tab index or None
"Get tab index by ID."@patch
def create_context(self:TabbedInterface,
request: Any, # FastHTML request object
sess: Any, # FastHTML session object
tab: Tab # Current tab
) -> InteractionContext: # Interaction context for rendering
"Create interaction context for a tab."@patch
def render_tabs(self:TabbedInterface,
current_tab_id: str, # Currently active tab ID
tab_route_func: Callable[[str], str] # Function to generate tab route
) -> FT: # Tab navigation element
"Render tab navigation using DaisyUI radio-based tabs."@patch
def render_tab_content(self:TabbedInterface,
tab_obj: Tab, # Tab to render
ctx: InteractionContext # Interaction context
) -> FT: # Tab content
"Render tab content."@patch
def render_full_interface(self:TabbedInterface,
current_tab_id: str, # Currently active tab ID
tab_route_func: Callable[[str], str], # Function to generate tab route
request: Any, # FastHTML request object
sess: Any # FastHTML session object
) -> FT: # Complete tabbed interface
"Render complete tabbed interface with tabs and content area."@patch
def create_router(self:TabbedInterface,
prefix: str = "" # URL prefix for routes (e.g., "/dashboard")
) -> APIRouter: # APIRouter with generated routes
"Create FastHTML router with generated routes for this tabbed interface."Classes
@dataclass
class Tab:
"Definition of a single tab in a tabbed interface."
id: str # Unique tab identifier (used in URLs)
label: str # Display label for the tab
render: Callable[[InteractionContext], Any] # Function to render tab content
title: Optional[str] # Optional title/tooltip for the tab
data_loader: Optional[Callable[[Any], Dict[str, Any]]] # Data loading function
load_on_demand: bool = True # Whether to load content only when tab is selectedclass TabbedInterface:
def __init__(
self,
interface_id: str, # Unique identifier for this interface
tabs_list: List[Tab], # List of tab definitions
default_tab: Optional[str] = None, # Default tab ID (defaults to first tab)
container_id: str = InteractionHtmlIds.TABBED_INTERFACE_CONTAINER, # HTML ID for container
tabs_id: str = InteractionHtmlIds.TABBED_INTERFACE_TABS, # HTML ID for tabs element
content_id: str = InteractionHtmlIds.TABBED_INTERFACE_CONTENT, # HTML ID for content area
tab_style: Optional[str] = None, # DaisyUI tab style (lift, bordered, boxed)
show_on_htmx_only: bool = False # Whether to show full page layout for non-HTMX requests
)
"Manage multi-tab interfaces with automatic route generation and HTMX content loading."
def __init__(
self,
interface_id: str, # Unique identifier for this interface
tabs_list: List[Tab], # List of tab definitions
default_tab: Optional[str] = None, # Default tab ID (defaults to first tab)
container_id: str = InteractionHtmlIds.TABBED_INTERFACE_CONTAINER, # HTML ID for container
tabs_id: str = InteractionHtmlIds.TABBED_INTERFACE_TABS, # HTML ID for tabs element
content_id: str = InteractionHtmlIds.TABBED_INTERFACE_CONTENT, # HTML ID for content area
tab_style: Optional[str] = None, # DaisyUI tab style (lift, bordered, boxed)
show_on_htmx_only: bool = False # Whether to show full page layout for non-HTMX requests
)
"Initialize tabbed interface manager."