From 257ea845883a4eaccfeb4ad2fc3c01e506a13cc0 Mon Sep 17 00:00:00 2001 From: cobyfrombrooklyn-bot Date: Wed, 25 Feb 2026 00:53:09 -0500 Subject: [PATCH] Fix duplicated TOC entries when chapter starts with h2+ When a chapter's markdown file starts with an h2 or lower heading (e.g. `## Section Title`), the 'on this page' sidebar feature would add it as a sub-entry, duplicating the chapter's existing SUMMARY.md sidebar link. This skips the first heading in the on-this-page list when its text matches the active sidebar link, preventing the duplication. Fixes #2995 --- crates/mdbook-html/front-end/templates/toc.js.hbs | 10 ++++++++++ tests/testsuite/toc.rs | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/crates/mdbook-html/front-end/templates/toc.js.hbs b/crates/mdbook-html/front-end/templates/toc.js.hbs index 1a9f751ccf..33205b1892 100644 --- a/crates/mdbook-html/front-end/templates/toc.js.hbs +++ b/crates/mdbook-html/front-end/templates/toc.js.hbs @@ -356,6 +356,16 @@ window.customElements.define('mdbook-sidebar-scrollbox', MDBookSidebarScrollbox) headers = Array.from(main.querySelectorAll('h2, h3, h4, h5, h6')) .filter(h => h.id !== '' && h.children.length && h.children[0].tagName === 'A'); + // Skip the first heading if its text matches the active sidebar link. + // This avoids duplicating the chapter title in the "on this page" list + // when a chapter's markdown starts with a heading (e.g. `## Section Title`) + // that matches its SUMMARY.md entry. + // See https://github.com/rust-lang/mdBook/issues/2995 + if (headers.length > 0 + && activeSection.textContent.trim() === headers[0].textContent.trim()) { + headers.shift(); + } + if (headers.length === 0) { return; } diff --git a/tests/testsuite/toc.rs b/tests/testsuite/toc.rs index 40bb0001e2..9d07d09488 100644 --- a/tests/testsuite/toc.rs +++ b/tests/testsuite/toc.rs @@ -141,6 +141,17 @@ fn check_link_target_fallback() { ); } +/// The "on this page" feature should skip the first heading if it matches +/// the active sidebar link text, to avoid duplicating the chapter title +/// when a chapter starts with an h2+ heading. +/// See . +#[test] +fn toc_js_deduplicates_first_heading() { + BookTest::from_dir("toc/basic_toc") + .check_file_contains("book/toc*.js", "activeSection.textContent.trim() === headers[0].textContent.trim()") + .check_file_contains("book/toc*.js", "headers.shift()"); +} + // Checks formatting of summary names with inline elements. #[test] fn summary_with_markdown_formatting() {