DEV Community

artydev
artydev

Posted on

FastHTML : dealing with Modals with the help of Hyperscript

Here is a nice way to open a modal in FastHTML and Hyperscript
There is absolutely no Javascript

from fasthtml.common import *

app, rt = fast_app(
    hdrs=(
        StyleX("./static/styledev.css"),
        Script(src="https://unpkg.com/hyperscript.org@0.9.12"),
    ),
    live=True,
)


@app.get("/modal")
def modal():
    return Div(
        Div(_="on click trigger closeModal", cls="modal-underlay"),
        Div(
            H1("Modal Dialog"),
            P("This is the modal content"),
            P("You can put anything here, like text, or a form, or an image."),
            Button("Close", _="on click trigger closeModal", cls="btn danger"),
            cls="modal-content",
        ),
        id="modal",
        _="on closeModal add .closing then wait for animationend then remove me",
    )


@app.get("/")
def home():
    return Div(
        H2("Modal with FastHTML and Hyperscript", style="text-align:center"),
        Button(
            "Open a Modal",
            hx_get="/modal",
            hx_target="body",
            hx_swap="beforeend",
            cls="btn primary",
        ),
    )

serve(port=3333) 

Enter fullscreen mode Exit fullscreen mode

The CSS part :

/***** MODAL DIALOG ****/
#modal {
    /* Underlay covers entire screen. */
    position: fixed;
    top:0px;
    bottom: 0px;
    left:0px;
    right:0px;
    background-color:rgba(0,0,0,0.5);
    z-index:1000;

    /* Flexbox centers the .modal-content vertically and horizontally */
    display:flex;
    flex-direction:column;
    align-items:center;

    /* Animate when opening */
    animation-name: fadeIn;
    animation-duration:150ms;
    animation-timing-function: ease;
}

#modal > .modal-underlay {
    /* underlay takes up the entire viewport. This is only
    required if you want to click to dismiss the popup */
    position: absolute;
    z-index: -1;
    top:0px;
    bottom:0px;
    left: 0px;
    right: 0px;
}

#modal > .modal-content {
    /* Position visible dialog near the top of the window */
    margin-top:10vh;

    /* Sizing for visible dialog */
    width:80%;
    max-width:600px;

    /* Display properties for visible dialog*/
    border:solid 1px #999;
    border-radius:8px;
    box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.3);
    background-color:white;
    padding:20px;

    /* Animate when opening */
    animation-name:zoomIn;
    animation-duration:150ms;
    animation-timing-function: ease;
}

#modal.closing {
    /* Animate when closing */
    animation-name: fadeOut;
    animation-duration:150ms;
    animation-timing-function: ease;
}

#modal.closing > .modal-content {
    /* Animate when closing */
    animation-name: zoomOut;
    animation-duration:150ms;
    animation-timing-function: ease;
}

@keyframes fadeIn {
    0% {opacity: 0;}
    100% {opacity: 1;}
}

@keyframes fadeOut {
    0% {opacity: 1;}
    100% {opacity: 0;}
}

@keyframes zoomIn {
    0% {transform: scale(0.9);}
    100% {transform: scale(1);}
}

@keyframes zoomOut {
    0% {transform: scale(1);}
    100% {transform: scale(0.9);}
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)