Reusable user interaction patterns for FastHTML applications including multi-step wizards, master-detail views, modal workflows, and other stateful UI orchestration patterns.
Project description
cjm-fasthtml-interactions
Install
pip install cjm_fasthtml_interactions
Project Structure
nbs/
├── core/ (2)
│ ├── 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
└── 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 # Pattern for navigation between pages of content with HTMX integration
├── 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: 9 notebooks across 2 directories
Module Dependencies
graph LR
core_context[core.context<br/>Interaction Context]
core_html_ids[core.html_ids<br/>HTML IDs]
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 Controls]
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_html_ids
patterns_step_flow --> core_context
patterns_tabbed_interface --> core_html_ids
patterns_tabbed_interface --> core_context
10 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.
The container displays a loading indicator initially and uses HTMX to load
content when triggered. Once loaded, the entire container is replaced with
the fetched content (by default using outerHTML swap).
Examples:
# Simple spinner loader
AsyncLoadingContainer(
container_id="my-content",
load_url="/api/get-content"
)
# With loading message
AsyncLoadingContainer(
container_id="dashboard-stats",
load_url="/api/stats",
loading_message="Loading statistics..."
)
# With skeleton content
AsyncLoadingContainer(
container_id="user-card",
load_url="/api/user/123",
loading_type=LoadingType.NONE,
skeleton_content=Div("User profile skeleton...", cls="skeleton")
)
# Delayed load (triggered by intersection)
AsyncLoadingContainer(
container_id="lazy-image",
load_url="/api/image/456",
trigger="intersect once"
)
"""
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 a 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_controls(context_id: str # Context identifier (e.g., "library", "search-results")
) -> str: # HTML ID for pagination controls
"Generate HTML ID for pagination controls in a specific context."
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 group
class 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 with customizable content and options.
The modal uses the native HTML `<dialog>` element with DaisyUI styling.
It can be shown programmatically using `modalId.showModal()` and closed
with `modalId.close()` or by clicking the backdrop/close button.
Examples:
# Simple modal with default settings
ModalDialog(
modal_id="info-modal",
content=Div(
H2("Information"),
P("This is important information.")
)
)
# Large modal with custom content ID for HTMX updates
ModalDialog(
modal_id="settings-modal",
content=Div("Loading...", id="settings-content"),
size=ModalSize.LARGE,
content_id="settings-content"
)
# Full-size modal without close button or backdrop
ModalDialog(
modal_id="fullscreen-modal",
content=Div("Full screen content"),
size=ModalSize.FULL,
show_close_button=False,
close_on_backdrop=False
)
# Custom size modal with auto-show
ModalDialog(
modal_id="custom-modal",
content=Div("Custom sized modal"),
size=ModalSize.CUSTOM,
custom_width="w-96",
custom_height="h-64",
auto_show=True
)
"""
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.
Examples:
# Simple trigger button
ModalTriggerButton(
modal_id="info-modal",
label="Show Info"
)
# Styled trigger button
ModalTriggerButton(
modal_id="settings-modal",
label="Settings",
button_cls=str(combine_classes(btn, btn_colors.primary))
)
"""
Classes
class ModalSize(Enum):
"Predefined size options for modal dialogs."
Pagination Controls (pagination.ipynb)
Pattern for navigation between pages of content with HTMX integration
Import
from cjm_fasthtml_interactions.patterns.pagination import (
PaginationStyle,
PaginationControls
)
Functions
def PaginationControls(
current_page: int, # Current page number (1-indexed)
total_pages: int, # Total number of pages
route_func: Callable[[int], str], # Function to generate route for a page number
target_id: str, # HTML ID of element to update with HTMX
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 string for page info
button_size: str = None, # Button size class (e.g., btn_sizes.sm)
container_cls: Optional[str] = None, # Additional classes for container
push_url: bool = True, # Whether to update URL with hx-push-url
**kwargs # Additional attributes for the container
) -> FT: # Div element with pagination controls
"""
Create pagination navigation controls with HTMX integration.
The controls provide Previous/Next navigation with automatic disabled states
at page boundaries. Uses HTMX for SPA-like page transitions without full
page reloads.
Examples:
# Simple pagination for media library
PaginationControls(
current_page=5,
total_pages=20,
route_func=lambda p: f"/library?page={p}",
target_id="library-content"
)
# With custom styling and text
PaginationControls(
current_page=1,
total_pages=10,
route_func=lambda p: media_rt.library.to(page=p, view="grid"),
target_id=HtmlIds.MAIN_CONTENT,
prev_text="← Back",
next_text="Forward →",
button_size=str(btn_sizes.sm)
)
# Compact style without page info
PaginationControls(
current_page=3,
total_pages=8,
route_func=lambda p: f"/results?page={p}",
target_id="results",
style=PaginationStyle.COMPACT
)
# Without URL updates (for modals/drawers)
PaginationControls(
current_page=2,
total_pages=5,
route_func=lambda p: f"/api/items?page={p}",
target_id="modal-content",
push_url=False
)
"""
Classes
class PaginationStyle(Enum):
"Display styles for pagination controls."
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.
Returns a dictionary with keys: 'active', 'disconnected', 'error', 'reconnecting'
Each value is a Span element with a status dot and optional text.
Examples:
# Default indicators
indicators = create_connection_status_indicators()
# Larger indicators without text
indicators = create_connection_status_indicators(
status_size="md",
show_text=False
)
# Always show text
indicators = create_connection_status_indicators(
hide_text_on_mobile=False
)
"""
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.
The script listens to HTMX SSE events and updates the status indicator based on
connection state. It handles automatic reconnection with exponential backoff,
server shutdown detection, and tab visibility changes.
Examples:
# Create indicators and monitor script
indicators = create_connection_status_indicators()
script = SSEConnectionMonitorScript(
connection_id="my-stream",
status_indicators=indicators
)
# Custom configuration
config = SSEConnectionConfig(
max_reconnect_attempts=5,
reconnect_delay=2000,
log_to_console=False
)
script = SSEConnectionMonitorScript(
connection_id="my-stream",
status_indicators=indicators,
config=config
)
"""
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.
Returns a tuple of (status_container, monitor_script) that should be added to your page.
The status container displays the current connection status, and the monitor script
manages the connection monitoring and updates.
Examples:
# Simple monitor with default settings
status, script = SSEConnectionMonitor(
connection_id="dashboard-stream"
)
# Custom configuration
config = SSEConnectionConfig(
max_reconnect_attempts=5,
reconnect_delay=2000
)
status, script = SSEConnectionMonitor(
connection_id="data-stream",
status_size="md",
config=config,
container_cls="my-custom-class"
)
# Use in page
def my_page():
status, script = SSEConnectionMonitor(connection_id="events")
return Div(
# Header with status
Div(
H1("Dashboard"),
status # Status indicator
),
# SSE connection element
Div(
hx_ext="sse",
sse_connect="/stream/events",
sse_swap="message",
id=InteractionHtmlIds.sse_element("events")
),
# Monitor script
script
)
"""
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 debugging
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 session."
@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 session."
@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 session."
@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 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
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
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
)
"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
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
)
"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 selected
class 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."
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cjm_fasthtml_interactions-0.0.20.tar.gz.
File metadata
- Download URL: cjm_fasthtml_interactions-0.0.20.tar.gz
- Upload date:
- Size: 65.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d7e3392bfcb5ea5b49c868773faa006dd3843811e38521a48b8971efc3eb727b
|
|
| MD5 |
af731e2fc9ae1b55cb14f7745566346d
|
|
| BLAKE2b-256 |
505f663e568050cc0bbc4371eceb4233ac2c472fc4b6abb6801fe0b3f1690c19
|
File details
Details for the file cjm_fasthtml_interactions-0.0.20-py3-none-any.whl.
File metadata
- Download URL: cjm_fasthtml_interactions-0.0.20-py3-none-any.whl
- Upload date:
- Size: 61.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56cd5a4dddb6dc77d59d09ebcf4cbd4490276b27bacde816c2c6bc5e575fdfaa
|
|
| MD5 |
9afdfee12ce8bdfa9c3a09cd90ffaea1
|
|
| BLAKE2b-256 |
cd84d32487cb651c0e50ef95b04026e3139fdaa402f66db56df633437e77b08d
|