How do I set the app Title with panel.serve?

I’m using panel.serve to serve a list of Panel applications.

I would like the index page to show a custom title in the browser tab like Corp Analytics

I would like each app to show a custom title in the browser tab like App Name.

How do I achieve that?

What I can do and would like is shown below

Index Page

App 1 Page

App 2 Page

Code

import panel as pn

def create_app():

    return pn.Spacer(background="green", sizing_mode="stretch_both")

APP_ROUTES = {

    "app1": create_app,

    "app2": create_app

}

pn.serve(APP_ROUTES, port=14033, title="My App")

One way I had hoped to achieve this was by giving each app a name

import panel as pn

def create_app_1():
    return pn.Spacer(background="green", sizing_mode="stretch_both", name="App1")

def create_app_2():
    return pn.Spacer(background="blue", sizing_mode="stretch_both", name="App2")

APP_ROUTES = {
    "app1": create_app_1,
    "app2": create_app_2,
}

pn.serve(APP_ROUTES, port=14033)

But that does not work either.

I have also tried using a Template without luck

import panel as pn

TEMPLATE = """
{% from macros import embed %}

<!DOCTYPE html>
<html lang="en">
{% block head %}
<head>
    {% block inner_head %}
    <meta charset="utf-8">
    <title>{% block title %}{{ title | e if title else "Panel App" }}{% endblock %}</title>
    {% block preamble %}{% endblock %}
    {% block resources %}
        {% block css_resources %}
        {{ bokeh_css | indent(8) if bokeh_css }}
        {% endblock %}
        {% block js_resources %}
        {{ bokeh_js | indent(8) if bokeh_js }}
        {% endblock %}
    {% endblock %}
    {% block postamble %}{% endblock %}
    {% endblock %}
</head>
{% endblock %}
{% block body %}
<body>
    {% block inner_body %}
    {% block contents %}
        {% for doc in docs %}
        {{ embed(doc) if doc.elementid }}
        {% for root in doc.roots %}
            {{ embed(root) | indent(10) }}
        {% endfor %}
        {% endfor %}
    {% endblock %}
    {{ plot_script | indent(8) }}
    {% endblock %}
</body>
{% endblock %}
</html>
"""

def create_app_1():
    content = pn.Spacer(background="green", sizing_mode="stretch_both", name="App1")
    template = pn.Template(
        template=TEMPLATE,
        items={"content": content},
    )
    template.add_variable('title', 'App1')
    return template


def create_app_2():
    return pn.Spacer(background="blue", sizing_mode="stretch_both", name="App2")

APP_ROUTES = {
    "app1": create_app_1,
    "app2": create_app_2,
}

pn.serve(APP_ROUTES, port=14033)

I tried simplifying the template

import panel as pn

TEMPLATE = """
{% extends base %}

{% block title %}
{{ title }}
{% endblock %}

{% block contents %}

{{ title }}

{% endblock %}
"""

def create_app_1():
    content = pn.Spacer(background="green", sizing_mode="stretch_both", name="App1")
    template = pn.Template(
        template=TEMPLATE,
        items={"content": content},
    )
    template.add_variable('title', 'App1')
    return template


def create_app_2():
    return pn.Spacer(background="blue", sizing_mode="stretch_both", name="App2")

APP_ROUTES = {
    "app1": create_app_1,
    "app2": create_app_2,
}

pn.serve(APP_ROUTES, port=14033)

But it shows

I then though. Ok it might be the title which is reserved/ overwritten by Panel.

And this shows the right title but not the right content.

import panel as pn

TEMPLATE = """
{% extends base %}

{% block title %}
{{ app_title }}
{% endblock %}

{% block contents %}

{{ app_title }}

{% endblock %}
"""

def create_app_1():
    content = pn.Spacer(background="green", sizing_mode="stretch_both", name="App1")
    template = pn.Template(
        template=TEMPLATE,
        items={"content": content},
    )
    template.add_variable('app_title', 'App1')
    return template


def create_app_2():
    return pn.Spacer(background="blue", sizing_mode="stretch_both", name="App2")

APP_ROUTES = {
    "app1": create_app_1,
    "app2": create_app_2,
}

pn.serve(APP_ROUTES, port=14033)

I would then have expected this to work but it did not.

import panel as pn

TEMPLATE = """
{% extends base %}

{% block title %}
{{ app_title }}
{% endblock %}

"""

def create_app_1():
    content = pn.Spacer(background="green", sizing_mode="stretch_both", name="App1")
    template = pn.Template(
        template=TEMPLATE,
        items={"content": content},
    )
    template.add_variable('app_title', 'App1')
    return template


def create_app_2():
    return pn.Spacer(background="blue", sizing_mode="stretch_both", name="App2")

APP_ROUTES = {
    "app1": create_app_1,
    "app2": create_app_2,
}

pn.serve(APP_ROUTES, port=14033)

1 Like

Try pn.curdoc.title = “Your title”

2 Likes

At least in Panel >=0.10 you can supply a dictionary for the title argument:

pn.serve(APP_ROUTES, title={'app1': 'Some title', 'app2': 'Some other title'}, port=14034)
2 Likes

Hi @Marc and @philippjfr.

I ran in the same trouble, but I might have found a lead.

I opened an issue in the GitHub repo as I consider this as a minor bug (@philippjfr I let you judge).

Here the link https://github.com/holoviz/panel/issues/1947