Can i use/create a modal/dialog in Panel?

I need to use a modal in my app.
Is there any existing solution?
if not, can you guide me on using HTML pane to do it?

Hi @ItamarShDev

How to solve this depends on what you want to do with the model.

Should it contain

  • Text
  • Markdown
  • Html
  • Panel Buttons
  • Panel layouts, panes or widgets?

I believe you would have to do one of the following.

I would try the first or second option depending on your use case.

And please add a Feature Request to Panel on Github describing your use case. That will help.

Hi @ItamarShDev

Did you find a solution? And which?

I think I will be experimenting a bit with this today as I need to learn about it too.

Regarding whether it’s in Panel 0.10 I’m not sure. I can see that there is a statement in that direction https://github.com/holoviz/panel/pull/1421#issuecomment-653582948 though.

Hi @ItamarShDev.

I’ve created an example based on a custom Panel Template.

Check it out live at https://awesome-panel.org/dialog_template

You can find the most recent code here https://github.com/MarcSkovMadsen/awesome-panel/tree/master/application/pages/dialog_template.

I include the current code below for completeness


template.html

{% extends base %}

{% block postamble %}
<!-- https://shoelace.style/ -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.19/dist/shoelace/shoelace.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.19/dist/shoelace/shoelace.esm.js"></script>
<style>
    body, .bk-root .bk, .bk-root .bk:before, .bk-root .bk:after {
        font-family: var(--sl-input-font-family);
    }
</style>
{% endblock %}

<!-- goes in body -->
{% block contents %}
{{ embed(roots.header) }}
<div id="main" style="margin: 25px">
    {{ embed(roots.main) }}
    <br/>
    <!-- https://shoelace.style/components/dialog -->
    <sl-dialog label="{{ dialog_label }}" class="dialog-overview" style="--width: 550px;--height: 500px;">
        {{ embed(roots.dialog) }}
    <sl-button slot="footer" type="primary">Close</sl-button>
    </sl-dialog>

    <sl-button>Open Dialog</sl-button>
</div>

<script>
(() => {
    const dialog = document.querySelector('.dialog-overview');
    const openButton = dialog.nextElementSibling;
    const closeButton = dialog.querySelector('sl-button[slot="footer"]');

    openButton.addEventListener('click', () => dialog.show());
    closeButton.addEventListener('click', () => dialog.hide());
})();
</script>

{% endblock %}

template.py

"""Custom Panel Template With a Dialog"""
import pathlib

import panel as pn
import param

TEMPLATE = (pathlib.Path(__file__).parent / "template.html").read_text()


class TemplateWithDialog(pn.template.Template):
    """Custom Panel Template With a Dialog"""

    dialog_open = param.Action()
    dialog_close = param.Action()

    TEMPLATE = (pathlib.Path(__file__).parent / "template.html").read_text()

    def __init__(self, header, main, dialog, dialog_label: str):
        super().__init__(
            template=TEMPLATE,
        )

        self.add_panel("header", header)
        self.add_panel("main", main)
        self.add_panel("dialog", dialog)
        self.add_variable("dialog_label", dialog_label)

app.py

"""Panel application show casing a Custom Panel Template With a Dialog"""
import hvplot.pandas  # pylint: disable=unused-import
import panel as pn
from bokeh.sampledata import sea_surface_temperature as sst

from .template import TemplateWithDialog


def _get_sea_surface_temperature_plot():
    if "dialog_template_plot" not in pn.state.cache:
        pn.state.cache["dialog_template_plot"] = sst.sea_surface_temperature.hvplot.kde().opts(
            height=300, width=500
        )
    return pn.state.cache["dialog_template_plot"]


def view():
    """Returns a Panel application show casing a Custom Panel Template With a Dialog"""
    top_panel = pn.Row(
            pn.pane.PNG(
                "https://panel.holoviz.org/_static/logo_horizontal.png",
                height=50,
                margin=10,
                link_url="https://panel.holoviz.org",
                sizing_mode="stretch_width",
            ),
            background="black",
            sizing_mode="stretch_width",
        )
    main_panel = pn.Column(
        "This is a Panel application with a dialog",
        "Provided by awesome-panel.org",
        sizing_mode="stretch_width",
    )
    dialog_panel = pn.Column(_get_sea_surface_temperature_plot(), sizing_mode="fixed")

    template = TemplateWithDialog(
        header=top_panel,
        main=main_panel,
        dialog=dialog_panel,
        dialog_label="HvPlot - Sea surface temperature kde",
    )

    return template
2 Likes

Very nice example! I’ve been wondering how to do that.

1 Like

We should learn more about custom templates @Jhsmit :+1:

With a component library like shoelace, fast, material Mwc, sap ui 5 etc you can actually create lots of awesome and modern layouts for you panel app.

Amazing! can we communicate with that example?

For example, get yes/no answer, get inputs values and such?

1 Like

Yes.

You can place any panel components inside the pn.Column of the dialog_panel. So replace the plot with markdown, checkboxes, radioboxes etc.

1 Like