Modal Dialog

Pattern for modal dialogs with customizable content, sizes, and actions

ModalDialog Function

The ModalDialog function creates a modal dialog component using DaisyUI’s modal system.

Key features: - Native HTML <dialog> element with DaisyUI styling - Customizable sizes (small, medium, large, xlarge, full, or custom) - Optional close button (top-right X button) - Optional backdrop for closing on outside click - Support for HTMX updates to modal content - Programmatic show/close via JavaScript API - Auto-show support for immediate display - Flexible content area with optional styling


source

ModalDialog


def ModalDialog(
    modal_id:str, # Unique identifier for the modal
    content:Any, # Content to display in the modal
    size:Union=<ModalSize.MEDIUM: 'md'>, # 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=None, # Optional ID for content area (for HTMX targeting)
    custom_width:Optional=None, # Custom width class (e.g., "w-96")
    custom_height:Optional=None, # Custom height class (e.g., "h-screen")
    box_cls:Optional=None, # Additional classes for modal box
    kwargs:VAR_KEYWORD
)->FT: # Dialog element with modal dialog configured

Create a modal dialog using native HTML dialog element with DaisyUI styling.

Trigger Button Helper

Helper function to create a button that opens a modal dialog.


source

ModalTriggerButton


def ModalTriggerButton(
    modal_id:str, # ID of the modal to trigger
    label:str, # Button label text
    button_cls:Optional=None, # Additional button classes
    kwargs:VAR_KEYWORD
)->FT: # Button element that triggers modal

Create a button that opens a modal dialog.

Usage Examples

Here are complete examples showing different modal use cases:

from cjm_fasthtml_daisyui.components.data_display.card import card_body, card_title
from cjm_fasthtml_daisyui.components.actions.button import btn_colors

# Example 1: Simple info modal
simple_modal = ModalDialog(
    modal_id="info",
    content=Div(
        H2("Information", cls=str(card_title)),
        P("This is a simple informational modal."),
        cls=str(card_body)
    ),
    size=ModalSize.SMALL
)

# Trigger button
trigger_btn = ModalTriggerButton(
    modal_id="info",
    label="Show Info",
    button_cls=str(btn_colors.info)
)

print("Example 1: Simple info modal")
print(f"Modal ID: {InteractionHtmlIds.modal_dialog('info')}")
print(f"Trigger: {trigger_btn}")
Example 1: Simple info modal
Modal ID: modal-info
Trigger: <button onclick="document.getElementById('modal-info').showModal()" class="btn btn-info">Show Info</button>
# Example 2: Large modal with HTMX content loading
from cjm_fasthtml_interactions.patterns.async_loading import AsyncLoadingContainer, LoadingType

# Modal with async loading content
loading_modal = ModalDialog(
    modal_id="settings",
    content=AsyncLoadingContainer(
        container_id="settings-form",
        load_url="/api/settings/form",
        loading_type=LoadingType.SPINNER,
        loading_message="Loading settings..."
    ),
    size=ModalSize.LARGE,
    content_id="settings-form"
)

print("Example 2: Modal with async content")
print(f"Modal ID: {InteractionHtmlIds.modal_dialog('settings')}")
print(f"Content ID: {InteractionHtmlIds.modal_dialog_content('settings')}")
Example 2: Modal with async content
Modal ID: modal-settings
Content ID: modal-settings-content
# Example 3: Full-screen modal for media viewing
fullscreen_modal = ModalDialog(
    modal_id="media-viewer",
    content=Div(
        Img(src="/images/large-photo.jpg", alt="Photo"),
        cls=combine_classes("flex", "items-center", "justify-center")
    ),
    size=ModalSize.FULL,
    show_close_button=True,
    close_on_backdrop=True
)

print("Example 3: Full-screen media viewer")
print(f"Modal ID: {InteractionHtmlIds.modal_dialog('media-viewer')}")
Example 3: Full-screen media viewer
Modal ID: modal-media-viewer
# Example 4: Custom size modal with auto-show
custom_modal = ModalDialog(
    modal_id="welcome",
    content=Div(
        H2("Welcome!", cls=str(card_title)),
        P("Thanks for visiting our app."),
        cls=str(card_body)
    ),
    size=ModalSize.CUSTOM,
    custom_width="w-96",
    custom_height="h-48",
    auto_show=True
)

print("Example 4: Custom size with auto-show")
print(f"Modal ID: {InteractionHtmlIds.modal_dialog('welcome')}")
Example 4: Custom size with auto-show
Modal ID: modal-welcome

Programmatic Control

You can show and close modals programmatically using JavaScript:

// Show modal
document.getElementById('modal-my-modal').showModal();

// Close modal
document.getElementById('modal-my-modal').close();

Or in Python, using the helper to generate the correct JavaScript:

# In your button onclick
Button(
    "Open Modal",
    onclick=f"document.getElementById('{InteractionHtmlIds.modal_dialog('my-modal')}').showModal()"
)

# Or use ModalTriggerButton helper
ModalTriggerButton(
    modal_id="my-modal",
    label="Open Modal"
)

HTMX Integration

Modals work seamlessly with HTMX for dynamic content updates:

Update Modal Content

Target the content area to update modal contents:

# Create modal with content ID
modal = ModalDialog(
    modal_id="details",
    content=Div("Initial content", id="details-content"),
    content_id="details-content"
)

# Button that updates modal content and shows it
Button(
    "Load Details",
    hx_get="/api/details/123",
    hx_target=InteractionHtmlIds.as_selector(
        InteractionHtmlIds.modal_dialog_content("details")
    ),
    hx_swap="innerHTML",
    # Show modal after content loads
    hx_on__after_swap=f"document.getElementById('{InteractionHtmlIds.modal_dialog('details')}').showModal()"
)

Close Modal After Action

Close modal after a successful form submission:

# Form inside modal
Form(
    # ... form fields ...
    Button("Save", type="submit"),
    hx_post="/api/save",
    # Close modal on success
    hx_on__after_request=f"""
        if (event.detail.successful) {{
            document.getElementById('{InteractionHtmlIds.modal_dialog('my-modal')}').close();
        }}
    """
)

Server-Side Responses

When updating modal content via HTMX, return just the content:

@app.get("/api/details/{id}")
def get_details(id: str):
    # Load data
    details = load_details(id)
    
    # Return just the content (will replace content area)
    return Div(
        H2(details["title"]),
        P(details["description"]),
        # Include ID to match target
        id=InteractionHtmlIds.modal_dialog_content("details")
    )

To show a modal from server-side response, use OOB swap:

@app.post("/api/trigger-action")
def trigger_action():
    # Perform action
    result = do_something()
    
    # Create modal with auto-show
    result_modal = ModalDialog(
        modal_id="result",
        content=Div(
            H2("Success!"),
            P(f"Action completed: {result}")
        ),
        auto_show=True
    )
    
    # Add OOB swap to inject modal into page
    result_modal.attrs['hx-swap-oob'] = 'beforeend:body'
    
    return Div(
        P("Action completed"),  # Main response
        result_modal  # OOB modal
    )