How to move / detach single pane from a dashboard into a separate browser window?

Hi there,

I have a panel dashboard, which works fine so far.
Now I’d like to move one of the components into a separate browser window, so I can move it around or maximize it on a 2nd screen. Apart from this changed placement, it should still behave as before, i.e. as a part of the dashboard, communicating with the other parts, etc.

Thanks for any pointers in a useful direction!

This works, but don’t use panel serve to launch. Just run it as a script. The Javascript tied to the open_input_window button might get stopped by a pop-up blocker.

import panel as pn
import param

class AppClass(param.Parameterized):
    text_input = param.String(default="input_string", doc="A string")
    output = pn.pane.Markdown('test')
    open_input_window = param.Event()

    @param.depends('text_input', on_init = True, watch = True)
    def markdown(self):
        self.output.object = self.text_input

app = AppClass()

button =   pn.widgets.Button.from_param(app.param['open_input_window'])

x ="2_input_window", '_blank', 'left=500,height=400,width=400')
""", args={})

    '1_start_here': pn.Row(app.output, button),
    '2_input_window': pn.Row(app.param['text_input'])
1 Like

Hi @ansgar-t

I have an example implementation below. The key idea is to save the component in pn.state.cache under a unique_id and then use that unique_id when opening in another window.

import panel as pn
import uuid


def get_object_id():
    return pn.state.session_args.get("id", [b""])[0].decode(encoding="utf8")

def serve_no_object_id_app():
    unique_id = str(uuid.uuid4()) 

    js_pane = pn.pane.HTML(visible=False, height=0, width=0, sizing_mode="fixed", margin=0)
    open_button = pn.widgets.Button(name = "Open the component below in another window", button_type="primary")
    component = pn.widgets.TextInput(name="Some component")
    @pn.depends(open_button, watch=True)
    def open_new_window(_):
        js_pane.object=f"""<script>"?id={unique_id}", '_blank', 'left=500,height=400,width=400')
        js_pane.object = ""

    pn.Column("# Main Page", open_button, component, js_pane).servable()

def serve_object_id_app(object_id):
    component = pn.state.cache.get(object_id, pn.pane.Markdown("Not found"))
    pn.Column(f"# Page {object_id}", component).servable()

object_id = get_object_id()

if not object_id:
panel serve

There are some open questions though? How to delete these components. It might not matter for small use cases. But if you are sharing with many users over a longer period of time these objects will take up more and more memory.


Is there some reason the documented pn.serve functionality doesn’t work?

1 Like

Depends on what you want to achieve. The main issue is that all users will share the same app because it’s not instantiated inside a function provided to pn.serve

Ahh. Good point. I didn’t think about that.

1 Like

Thanks, guys! Will try it out soon!