Download this notebook from GitHub (right-click to download).

import idom

import panel as pn


WARNING: Currently Panel only support idom version 0.24. We are working on supporting later version as part of the idom-bokeh project.

The IDOM pane renders any IDOM component both in the notebook and in a deployed server. IDOM defines an API for defining and controlling interactive HTML components directly from Python. Note that in the notebook the IDOM support for loading external modules relies on Panel’s Jupyter serverextension. To check if this is enabled you can run:

jupyter serverextension list

You should see:  enabled
- Validating...  OK

If you don’t see this but have installed panel you can manually enable the server extension with:

jupyter serverextension enable --sys-prefix

which will install it where your Python is installed or to place it in the Jupyter config in your home directory:

jupyter serverextension enable --py panel


For layout and styling related parameters see the customization user guide.

  • object (object): The IDOM component being displayed


  • default_layout (pn.layout.Panel, default=Row): Layout to wrap the plot and widgets in

The panel function will automatically convert any idom.component into a displayable panel, while keeping all of its interactive features:

def ClickCount():
    count, set_count = idom.hooks.use_state(0)

    return idom.html.button(
        {"onClick": lambda event: set_count(count + 1)},
        [f"Click count: {count}"],

pn.pane.IDOM(ClickCount, width=300)

This makes it possible to generate even complex interactive components directly from Python, e.g. here we will create a ToDo list:

def Todo():
    items, set_items = idom.hooks.use_state([])

    async def add_new_task(event):
        if event["key"] == "Enter":
            set_items(items + [event["value"]])

    tasks = []

    for index, text in enumerate(items):

        async def remove_task(event, index=index):
            set_items(items[:index] + items[index + 1 :])

        task_text =
        delete_button ={"onClick": remove_task}, idom.html.button(["x"]))
        tasks.append(, delete_button))

    task_input = idom.html.input({"onKeyDown": add_new_task})
    task_table = idom.html.table(tasks)

    return idom.html.div(task_input, task_table)


If you have a live server backing your session, whether that is a notebook server or a Bokeh/Panel server deployment you can also use external Javascript components which will be compiled before first use. See the idom documentation for more details on using external components. Note that to ensure that the JS modules are installed in the correct place you should use pn.pane.IDOM.install rather than simply using idom.install:

victory = pn.pane.IDOM.install("victory", fallback="loading...")

victory_com = idom.component(
    lambda: victory.VictoryBar({"style": {"parent": {"width": "500px"}}}),

2022-10-29T10:32:31+0000 | INFO | Installing dependencies...
2022-10-29T10:32:40+0000 | INFO | Installed successfully ✅
2022-10-29T10:32:40+0000 | INFO | Building client ...
2022-10-29T10:32:49+0000 | INFO | Client built successfully ✅

In order to work with Panel components seamlessly the IDOM pane also provides a use_param method which allows us to use the current parameter value much like we would when using pn.depends:

aw = pn.widgets.IntSlider(name='a', start=0, end=20, value=1)
bw = pn.widgets.IntSlider(name='b', start=0, end=20, value=1)

def view():
    a = pn.pane.IDOM.use_param(aw)
    b = pn.pane.IDOM.use_param(bw.param.value) # equivalent to passing in the widget
    return idom.html.div({}, f'{a}+{b}={a+b}')

pn.Row(aw, bw, view)
This web page was generated from a Jupyter notebook and not all interactivity will work on this website. Right click to download and run locally for full Python-backed interactivity.

Download this notebook from GitHub (right-click to download).