modal

Modal is used to show a dialog or a box when you click a button.

Base Modal Components

Exported source
modal = SingleValueFactory("modal", "Modal container component") # Modal container
modal_box = SingleValueFactory("modal-box", "The content part of modal") # Modal content box
modal_action = SingleValueFactory("modal-action", "Actions part of modal (buttons, etc.)") # Modal actions
modal_backdrop = SingleValueFactory("modal-backdrop", "Label that covers the page when modal is open") # Modal backdrop
modal_toggle = SingleValueFactory("modal-toggle", "Hidden checkbox that controls the state of modal") # Modal toggle

test_modal_basic_examples

 test_modal_basic_examples ()

Test basic modal utilities.

Exported source
def test_modal_basic_examples():
    """Test basic modal utilities."""
    assert str(modal) == "modal"
    assert str(modal_box) == "modal-box"
    assert str(modal_action) == "modal-action"
    assert str(modal_backdrop) == "modal-backdrop"
    assert str(modal_toggle) == "modal-toggle"
    assert str(modal_open) == "modal-open"

# Run the tests
test_modal_basic_examples()

source

test_modal_placement_examples

 test_modal_placement_examples ()

Test modal placement options.

Exported source
def test_modal_placement_examples():
    """Test modal placement options."""
    assert str(modal_placement.top) == "modal-top"
    assert str(modal_placement.middle) == "modal-middle"
    assert str(modal_placement.bottom) == "modal-bottom"
    assert str(modal_placement.start) == "modal-start"
    assert str(modal_placement.end) == "modal-end"

# Run the tests
test_modal_placement_examples()

source

test_modal_dialog_fasthtml_examples

 test_modal_dialog_fasthtml_examples ()

Test modal examples using HTML dialog element (recommended method).

Exported source
def test_modal_dialog_fasthtml_examples():
    """Test modal examples using HTML dialog element (recommended method)."""
    from fasthtml.common import Dialog, Div, Button, H3, P, Form
    from cjm_fasthtml_tailwind.utilities.spacing import p
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_tailwind.utilities.sizing import w, max_w
    from cjm_fasthtml_tailwind.utilities.layout import position, right, top
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_sizes, btn_modifiers, btn_styles
    
    # Basic dialog modal
    dialog_modal = Dialog(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("Press ESC key or click the button below to close", cls=p.y._4),
            Div(
                Form(
                    Button("Close", cls=str(btn)),
                    method="dialog"
                ),
                cls=str(modal_action)
            ),
            cls=str(modal_box)
        ),
        id="my_modal_1",
        cls=str(modal)
    )
    assert dialog_modal.tag == "dialog"
    assert dialog_modal.attrs['id'] == "my_modal_1"
    assert "modal" in dialog_modal.attrs['class']
    assert "modal-box" in dialog_modal.children[0].attrs['class']
    assert "modal-action" in dialog_modal.children[0].children[2].attrs['class']
    
    # Dialog modal with backdrop (closes when clicked outside)
    backdrop_modal = Dialog(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("Press ESC key or click outside to close", cls=p.y._4),
            cls=str(modal_box)
        ),
        Form(
            Button("close"),
            method="dialog",
            cls=str(modal_backdrop)
        ),
        id="my_modal_2",
        cls=str(modal)
    )
    assert "modal-backdrop" in backdrop_modal.children[1].attrs['class']
    assert backdrop_modal.children[1].tag == "form"
    assert backdrop_modal.children[1].attrs['method'] == "dialog"
    
    # Dialog modal with close button at corner
    close_button_modal = Dialog(
        Div(
            Form(
                Button(
                    "✕",
                    cls=combine_classes(
                        btn,
                        btn_sizes.sm,
                        btn_modifiers.circle,
                        btn_styles.ghost,
                        position.absolute,
                        right._2,
                        top._2
                    )
                ),
                method="dialog"
            ),
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("Press ESC key or click on ✕ button to close", cls=p.y._4),
            cls=str(modal_box)
        ),
        id="my_modal_3",
        cls=str(modal)
    )
    assert "btn-sm" in close_button_modal.children[0].children[0].children[0].attrs['class']
    assert "btn-circle" in close_button_modal.children[0].children[0].children[0].attrs['class']
    assert "absolute" in close_button_modal.children[0].children[0].children[0].attrs['class']
    assert "right-2" in close_button_modal.children[0].children[0].children[0].attrs['class']
    assert "top-2" in close_button_modal.children[0].children[0].children[0].attrs['class']
    
    # Dialog modal with custom width
    wide_modal = Dialog(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("Click the button below to close", cls=p.y._4),
            Div(
                Form(
                    Button("Close", cls=str(btn)),
                    method="dialog"
                ),
                cls=str(modal_action)
            ),
            cls=combine_classes(modal_box, w("11/12"), max_w._5xl)
        ),
        id="my_modal_4",
        cls=str(modal)
    )
    assert "w-11/12" in wide_modal.children[0].attrs['class']
    assert "max-w-5xl" in wide_modal.children[0].attrs['class']
    
    # Responsive modal (bottom on mobile, middle on larger screens)
    responsive_modal = Dialog(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("Press ESC key or click the button below to close", cls=p.y._4),
            Div(
                Form(
                    Button("Close", cls=str(btn)),
                    method="dialog"
                ),
                cls=str(modal_action)
            ),
            cls=str(modal_box)
        ),
        id="my_modal_5",
        cls=combine_classes(modal, modal_placement.bottom, modal_placement.middle.sm)
    )
    assert "modal-bottom" in responsive_modal.attrs['class']
    assert "sm:modal-middle" in responsive_modal.attrs['class']
    
    # Test button triggers with onclick
    trigger_button = Button(
        "open modal",
        cls=str(btn),
        onclick="my_modal_1.showModal()"
    )
    assert trigger_button.attrs['onclick'] == "my_modal_1.showModal()"
    
    # Return all elements in a Div
    return Div(
        trigger_button,
        dialog_modal,
        backdrop_modal,
        close_button_modal,
        wide_modal,
        responsive_modal
    )

# Run the tests
test_modal_dialog_fasthtml_examples()
<div>
<button onclick="my_modal_1.showModal()" class="btn">open modal</button><dialog id="my_modal_1" class="modal">    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">Press ESC key or click the button below to close</p>
      <div class="modal-action">
<form enctype="multipart/form-data" method="dialog"><button class="btn">Close</button></form>      </div>
    </div>
</dialog><dialog id="my_modal_2" class="modal">    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">Press ESC key or click outside to close</p>
    </div>
<form enctype="multipart/form-data" method="dialog" class="modal-backdrop"><button>close</button></form></dialog><dialog id="my_modal_3" class="modal">    <div class="modal-box">
<form enctype="multipart/form-data" method="dialog"><button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button></form>      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">Press ESC key or click on ✕ button to close</p>
    </div>
</dialog><dialog id="my_modal_4" class="modal">    <div class="modal-box w-11/12 max-w-5xl">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">Click the button below to close</p>
      <div class="modal-action">
<form enctype="multipart/form-data" method="dialog"><button class="btn">Close</button></form>      </div>
    </div>
</dialog><dialog id="my_modal_5" class="modal modal-bottom sm:modal-middle">    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">Press ESC key or click the button below to close</p>
      <div class="modal-action">
<form enctype="multipart/form-data" method="dialog"><button class="btn">Close</button></form>      </div>
    </div>
</dialog></div>
test_func = test_modal_dialog_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_modal_checkbox_fasthtml_examples

 test_modal_checkbox_fasthtml_examples ()

Test modal examples using checkbox method (legacy).

Exported source
def test_modal_checkbox_fasthtml_examples():
    """Test modal examples using checkbox method (legacy)."""
    from fasthtml.common import Label, Input, Div, H3, P
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_tailwind.utilities.spacing import p
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_sizes, btn_modifiers, btn_styles
    
    # Basic checkbox modal components
    checkbox_trigger = Label("open modal", for_="my_modal_6", cls=str(btn))
    checkbox_input = Input(type="checkbox", id="my_modal_6", cls=str(modal_toggle))
    checkbox_modal = Div(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("This modal works with a hidden checkbox!", cls=p.y._4),
            Div(
                Label("Close!", for_="my_modal_6", cls=str(btn)),
                cls=str(modal_action)
            ),
            cls=str(modal_box)
        ),
        cls=str(modal),
        role="dialog"
    )
    
    # Verify checkbox modal structure
    assert checkbox_trigger.attrs['for-'] == "my_modal_6"
    assert checkbox_trigger.attrs['class'] == "btn"
    assert checkbox_input.attrs['type'] == "checkbox"
    assert checkbox_input.attrs['id'] == "my_modal_6"
    assert "modal-toggle" in checkbox_input.attrs['class']
    assert checkbox_modal.attrs['role'] == "dialog"
    assert "modal" in checkbox_modal.attrs['class']
    
    # Checkbox modal that closes when clicked outside
    backdrop_checkbox_trigger = Label("open modal", for_="my_modal_7", cls=str(btn))
    backdrop_checkbox_input = Input(type="checkbox", id="my_modal_7", cls=str(modal_toggle))
    backdrop_checkbox_modal = Div(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("This modal works with a hidden checkbox!", cls=p.y._4),
            cls=str(modal_box)
        ),
        Label("Close", cls=str(modal_backdrop), for_="my_modal_7"),
        cls=str(modal),
        role="dialog"
    )
    
    # Verify backdrop structure
    assert backdrop_checkbox_modal.children[1].tag == "label"
    assert "modal-backdrop" in backdrop_checkbox_modal.children[1].attrs['class']
    assert backdrop_checkbox_modal.children[1].attrs['for-'] == "my_modal_7"
    
    # Full checkbox modal example
    full_checkbox_example = [
        checkbox_trigger,
        checkbox_input,
        checkbox_modal
    ]
    assert len(full_checkbox_example) == 3
    assert full_checkbox_example[0].tag == "label"
    assert full_checkbox_example[1].tag == "input"
    assert full_checkbox_example[2].tag == "div"
    
    # Return all elements in a Div
    return Div(
        checkbox_trigger,
        checkbox_input,
        checkbox_modal,
        backdrop_checkbox_trigger,
        backdrop_checkbox_input,
        backdrop_checkbox_modal
    )

# Run the tests
test_modal_checkbox_fasthtml_examples()
<div>
<label for-="my_modal_6" class="btn">open modal</label>  <input type="checkbox" id="my_modal_6" class="modal-toggle" name="my_modal_6">
  <div role="dialog" class="modal">
    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">This modal works with a hidden checkbox!</p>
      <div class="modal-action">
<label for-="my_modal_6" class="btn">Close!</label>      </div>
    </div>
  </div>
<label for-="my_modal_7" class="btn">open modal</label>  <input type="checkbox" id="my_modal_7" class="modal-toggle" name="my_modal_7">
  <div role="dialog" class="modal">
    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">This modal works with a hidden checkbox!</p>
    </div>
<label for-="my_modal_7" class="modal-backdrop">Close</label>  </div>
</div>
test_func = test_modal_checkbox_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_modal_anchor_fasthtml_examples

 test_modal_anchor_fasthtml_examples ()

Test modal examples using anchor links (legacy method).

Exported source
def test_modal_anchor_fasthtml_examples():
    """Test modal examples using anchor links (legacy method)."""
    from fasthtml.common import A, Div, H3, P
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_tailwind.utilities.spacing import p
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_sizes, btn_modifiers, btn_styles
    
    # Anchor link trigger
    anchor_trigger = A("open modal", href="#my_modal_8", cls=str(btn))
    
    # Anchor modal
    anchor_modal = Div(
        Div(
            H3("Hello!", cls=combine_classes(font_size.lg, font_weight.bold)),
            P("This modal works with anchor links", cls=p.y._4),
            Div(
                A("Yay!", href="#", cls=str(btn)),
                cls=str(modal_action)
            ),
            cls=str(modal_box)
        ),
        cls=str(modal),
        role="dialog",
        id="my_modal_8"
    )
    
    # Verify anchor modal structure
    assert anchor_trigger.attrs['href'] == "#my_modal_8"
    assert anchor_trigger.attrs['class'] == "btn"
    assert anchor_modal.attrs['id'] == "my_modal_8"
    assert anchor_modal.attrs['role'] == "dialog"
    assert "modal" in anchor_modal.attrs['class']
    
    # Verify the close button
    close_link = anchor_modal.children[0].children[2].children[0]
    assert close_link.tag == "a"
    assert close_link.attrs['href'] == "#"
    assert "btn" in close_link.attrs['class']
    
    # Test with :target pseudo-class (conceptual)
    # Note: The actual :target CSS pseudo-class behavior happens in the browser
    # when the URL fragment matches the element's ID
    modal_with_target = Div(
        anchor_trigger,
        anchor_modal,
        cls="modal-container"
    )
    assert len(modal_with_target.children) == 2
    assert modal_with_target.children[0].attrs['href'] == "#my_modal_8"
    assert modal_with_target.children[1].attrs['id'] == "my_modal_8"
    
    # Return all elements in a Div
    return Div(
        anchor_trigger,
        anchor_modal,
    )

# Run the tests
test_modal_anchor_fasthtml_examples()
<div>
<a href="#my_modal_8" class="btn">open modal</a>  <div role="dialog" id="my_modal_8" class="modal">
    <div class="modal-box">
      <h3 class="text-lg font-bold">Hello!</h3>
      <p class="py-4">This modal works with anchor links</p>
      <div class="modal-action">
<a href="#" class="btn">Yay!</a>      </div>
    </div>
  </div>
</div>
test_func = test_modal_anchor_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()