From 34e9d2125bd47d236e1a3023b2b8efa792a9702b Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Sat, 8 Aug 2026 16:07:37 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20don=E2=80=99t=20show=20navbar=20if?= =?UTF-8?q?=20the=20user=20doesn=E2=80=99t=20ask=20for=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/sections/header.md | 4 +++- src/sphinx_book_theme/__init__.py | 10 +++++++++ .../theme/sphinx_book_theme/layout.html | 8 +++++++ tests/test_build.py | 22 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/sections/header.md b/docs/sections/header.md index c637a6335..e979100d9 100644 --- a/docs/sections/header.md +++ b/docs/sections/header.md @@ -6,7 +6,7 @@ If any of this configuration is set, then your header will show at the top of th ## Add components to the header navbar -There are three configuration options you can use in `html_theme_options`: +There are four configuration options you can use in `html_theme_options`: **`navbar_start`**: Adds components to the beginning of the header. **Visible on all screen sizes**. Use this for adding a logo that you want to persist over time. @@ -14,6 +14,8 @@ There are three configuration options you can use in `html_theme_options`: **`navbar_end`**: Adds components to the end of the header. **Moved to the sizebar on mobile**. Use this for extra social links or buttons. +**`navbar_persistent`**: Adds components to the end of the header that stay there on mobile rather than moving to the sidebar. + ## An example For example, you can add a button to the header like so: diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 4c583c977..9c4ccdb63 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -166,6 +166,15 @@ def update_mode_thebe_config(app): app.env.config.thebe_config = thebe_config +def update_navbar_defaults(app): + """Keep the top navbar empty unless the user asks for something in it. + + Without this, the pydata theme adds a search button to the navbar. + """ + theme_options = get_theme_options_dict(app) + theme_options.setdefault("navbar_persistent", []) + + def check_deprecation_keys(app): """Warns about the deprecated keys.""" @@ -218,6 +227,7 @@ def setup(app: Sphinx): app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir) # Events + app.connect("builder-inited", update_navbar_defaults, priority=400) # before pydata theme app.connect("builder-inited", update_mode_thebe_config) app.connect("builder-inited", check_deprecation_keys) app.connect("builder-inited", update_sourcename) diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html index 0d56fc1f1..d50761fcf 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html @@ -1,6 +1,14 @@ {% extends "pydata_sphinx_theme/layout.html" %} {# ref: https://github.com/pydata/pydata-sphinx-theme/blob/master/src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html #} +{# Skip
when no navbar area has any content in it. #} +{% block docs_navbar %} +{%- if theme_navbar_start or theme_navbar_center or theme_navbar_end or theme_navbar_persistent %} +{{ super() }} +{%- endif %} +{% endblock docs_navbar %} + + {% block docs_main %} {# A tiny helper pixel to detect if we've scrolled #}
diff --git a/tests/test_build.py b/tests/test_build.py index 360a01f09..a80aba9f1 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -151,6 +151,28 @@ def test_navbar_options_home_page_in_toc(sphinx_build_factory): assert "Index with code in title" in str(li) +def test_no_navbar_by_default(sphinx_build_factory): + """The top navbar is opt-in, so nothing should be rendered for it.""" + sphinx_build = sphinx_build_factory("base").build( + assert_pass=True + ) # type: SphinxBuild + index = sphinx_build.html_tree("index.html") + assert index.find(id="pst-header") is None + # The only search button is the one in the primary sidebar + search_buttons = index.select("button.search-button-field") + assert len(search_buttons) == 1 + assert search_buttons[0].find_parent(id="pst-primary-sidebar") is not None + + +def test_navbar_opt_in(sphinx_build_factory): + """Filling in any navbar area brings the top navbar back.""" + sphinx_build = sphinx_build_factory( + "base", + confoverrides={"html_theme_options.navbar_center": ["navbar-nav.html"]}, + ).build(assert_pass=True) # type: SphinxBuild + assert sphinx_build.html_tree("index.html").find(id="pst-header") is not None + + @pytest.mark.parametrize( "option,value", [ From f8ddb0397dc56e65b633186aa5de210b4152c6a0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 14:08:24 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/sphinx_book_theme/__init__.py | 4 +++- tests/test_build.py | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 9c4ccdb63..130959db8 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -227,7 +227,9 @@ def setup(app: Sphinx): app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir) # Events - app.connect("builder-inited", update_navbar_defaults, priority=400) # before pydata theme + app.connect( + "builder-inited", update_navbar_defaults, priority=400 + ) # before pydata theme app.connect("builder-inited", update_mode_thebe_config) app.connect("builder-inited", check_deprecation_keys) app.connect("builder-inited", update_sourcename) diff --git a/tests/test_build.py b/tests/test_build.py index a80aba9f1..5fb1c9f0f 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -153,9 +153,7 @@ def test_navbar_options_home_page_in_toc(sphinx_build_factory): def test_no_navbar_by_default(sphinx_build_factory): """The top navbar is opt-in, so nothing should be rendered for it.""" - sphinx_build = sphinx_build_factory("base").build( - assert_pass=True - ) # type: SphinxBuild + sphinx_build = sphinx_build_factory("base").build(assert_pass=True) # type: SphinxBuild index = sphinx_build.html_tree("index.html") assert index.find(id="pst-header") is None # The only search button is the one in the primary sidebar