Embed Anvil app in floating iframe with gray overlay, similar to an alert

I would like to show an Anvil app in an iframe, floating over the rest of the page, similar to what we see in an Anvil alert. I would like for the app to take the whole window, with a 5% margin all around where you see the parent document a little grayed out.

The following code shows my attempt, which is close, but has a two problems:

  • When the form is small, the margin is 5% on left, top and right, but it’s bigger on bottom
  • When the form is large, the form spills down and is not scrollable

How do I change this to make the embedded div always the same size, and show a vertical scrollbar when the form is taller?

I tried with overflow-y: auto and other seemingly obvious solutions, but I had no luck.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        /* Apply fixed position to the iframe */
        #anvil_app {
            position: fixed;
            top: 5%;
            left: 5%;
            width: 90%;
            height: 90%;
            border: 2px solid black;
            z-index: 999;
        }

        /* Add styles for overlay when iframe is hidden */
        #overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 998;
        }
    </style>
</head>
<body>
    I'm above the app.<br>
    <button type="button" onclick="showAppClick()">Show app</button><br>
    <button type="button" onclick="hideAppClick()">Hide app</button><br>
    <div id="overlay">
        <iframe id="anvil_app" data-anvil-embed
            src="https://<APP-URL>">
        </iframe>
    </div>
    <script src="https://anvil.works/embed.js" async></script>
    <script type="text/javascript">
        window.addEventListener("message", function(event) {
            if (event.origin !== "<APP-URL>")
                return;

            if (event.data === "cancel" || event.data === "ok") {
                hideAppClick();
            }
        });

        function showAppClick() {
            console.log('showAppClick');
            var overlay = document.getElementById("overlay");
            overlay.style.display = "block";
        }

        function hideAppClick() {
            console.log('hideAppClick');
            var overlay = document.getElementById("overlay");
            overlay.style.display = "none";
        }
    </script>
    I'm below the app.<br>
</body>
</html>

Here is the solution that seems to be working the way I like and I may be going with:

<script type="text/javascript">
window.addEventListener("message", function(event) {
    if (event.origin !== "<APP-URL>")
        return;

    if (event.data === "cancel")
        hideShipmentConfigurator();

    if (event.data === "ok") {
        // simulate two clicks on two buttons so OpenCart (the php app the 
        // Anvil app is embedded into) will digest the info calculated by 
        // the Anvil app
        $('a[href="#collapse-shipping-address"]').click();
        $("#button-shipping-address").click();
    }
});

function showShipmentConfigurator() {
    var div = document.getElementById("anvil_app_div");
    var iframe = document.getElementById("anvil_app");
    var overlay = document.getElementById("anvil_app_overlay");
    iframe.src = "<APP-URL>#?session_id=<?php echo $session_id; ?>";
    div.style.display = "";
    overlay.style.display = "block";
}

function hideShipmentConfigurator() {
    console.log('hideShipmentConfigurator');
    var div = document.getElementById("anvil_app_div");
    var overlay = document.getElementById("anvil_app_overlay");
    div.style.display = "none";
    overlay.style.display = "none";
}
</script>
<script src="https://anvil.works/embed.js" async></script>
<div
    id="anvil_app_div"
    style="
        display: none;
        position: fixed;
        top: 5%;
        left: 5%;
        width: 90%;
        height: 90%;
        overflow: auto;
        z-index: 999;
    "
>
    <iframe
        id="anvil_app"
        width="100%"
        data-anvil-embed>
    </iframe>
</div>
<div
    id="anvil_app_overlay"
    style="
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 998;
    "
>
</div>

The OK and Cancel buttons in the app do:

def cancel_click(self, **event_args):
    anvil.js.window.parent.postMessage('cancel', '*')

def ok_click(self, **event_args):
    <do something>
    anvil.js.window.parent.postMessage('ok', '*')
1 Like