Repository: plotly/dash

Issue:
dash title design issues
Title logic problem, when instantiating dash, title was set, when registering route, it was not set, should title when instantiating dash be used instead of module name? You can set the title of a single page when registering routes, but if the title of all pages is the same, is the code redundant, is there any other way to set the title globally, and only need to set it once


Discussion:
I'm not entirely clear on the objective of your question. The title set in `dash.Dash()` is the default title for the application. If you're looking for a more flexible and dynamic way to update the title, you might consider utilizing this component: https://fuc.feffery.tech/FefferySetTitle.
@jaxonister I agree that It would be convenient to be able to set the app title (and perhaps even the app description for the meta tags) and have it apply to all pages.

@alexcjohnson  - If we made its so, would this be considered a breaking change for the title?  It seems reasonable to assume it would work this way.      
Title, favicon.ico, all have such problems. normally, the title and favicon of a website are unified, and not each page is set differently. in fact, if instantiated, it is OK to set it once. if a page needs to be set separately, it can be set separately when registering layout. I think this design is better. I hope to adopt it.

Resolving patch:
diff --git a/dash/_pages.py b/dash/_pages.py
--- a/dash/_pages.py
+++ b/dash/_pages.py
@@ -235,13 +235,14 @@ def register_page(
        order `0`
 
     - `title`:
-       (string or function) The name of the page <title>. That is, what appears in the browser title.
-       If not supplied, will use the supplied `name` or will be inferred by module,
-       e.g. `pages.weekly_analytics` to `Weekly analytics`
+       (string or function) Specifies the page title displayed in the browser tab.
+        If not supplied, the app's title is used if different from the default "Dash".
+        Otherwise, the title is the given `name` or inferred from the module name.
+        For example, `pages.weekly_analytics` is inferred as "Weekly Analytics".
 
     - `description`:
        (string or function) The <meta type="description"></meta>.
-       If not supplied, then nothing is supplied.
+       If not defined, the application description will be used if available.
 
     - `image`:
        The meta description image used by social media platforms.
@@ -319,10 +320,18 @@ def register_page(
     )
     page.update(
         supplied_title=title,
-        title=(title if title is not None else page["name"]),
+        title=title
+        if title is not None
+        else CONFIG.title
+        if CONFIG.title != "Dash"
+        else page["name"],
     )
     page.update(
-        description=description if description else "",
+        description=description
+        if description
+        else CONFIG.description
+        if CONFIG.description
+        else "",
         order=order,
         supplied_order=order,
         supplied_layout=layout,
diff --git a/dash/dash.py b/dash/dash.py
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -366,6 +366,9 @@ class Dash:
     functions. The syntax for this parameter is a dict of State objects:
     `routing_callback_inputs={"language": Input("language", "value")}`
     NOTE: the keys "pathname_" and "search_" are reserved for internal use.
+
+    :param description:  Sets a default description for meta tags on Dash pages (use_pages=True).
+
     """
 
     _plotlyjs_url: str
@@ -404,6 +407,7 @@ def __init__(  # pylint: disable=too-many-statements
         add_log_handler=True,
         hooks: Union[RendererHooks, None] = None,
         routing_callback_inputs: Optional[Dict[str, Union[Input, State]]] = None,
+        description=None,
         **obsolete,
     ):
         _validate.check_obsolete(obsolete)
@@ -458,6 +462,7 @@ def __init__(  # pylint: disable=too-many-statements
             title=title,
             update_title=update_title,
             include_pages_meta=include_pages_meta,
+            description=description,
         )
         self.config.set_read_only(
             [


Test patch:
diff --git a/tests/integration/multi_page/test_pages_layout.py b/tests/integration/multi_page/test_pages_layout.py
--- a/tests/integration/multi_page/test_pages_layout.py
+++ b/tests/integration/multi_page/test_pages_layout.py
@@ -235,3 +235,27 @@ def test_pala005_routing_inputs(dash_duo, clear_pages_state):
     # Changing the language Input re-runs the layout function
     dash_duo.select_dcc_dropdown("#language", "fr")
     dash_duo.wait_for_text_to_equal("#contents", "Le hash dit: #123")
+
+
+def get_app_title_description():
+    app = Dash(
+        __name__, use_pages=True, title="App Title", description="App Description"
+    )
+    dash.register_page("home", layout=html.Div("Home"), path="/")
+    dash.register_page(
+        "page1",
+        layout=html.Div("Page1"),
+        title="Page 1 Title",
+        description="Page 1 Description",
+    )
+    app.layout = html.Div(dash.page_container)
+    return app
+
+
+def test_pala006_app_title_discription(dash_duo, clear_pages_state):
+    dash_duo.start_server(get_app_title_description())
+
+    assert dash.page_registry["home"]["title"] == "App Title"
+    assert dash.page_registry["page1"]["title"] == "Page 1 Title"
+    assert dash.page_registry["home"]["description"] == "App Description"
+    assert dash.page_registry["page1"]["description"] == "Page 1 Description"