Skip to content

Nav sections: independent sidebar islands and dynamic top bar#3133

Open
theletterf wants to merge 29 commits into
nav-v2from
nav-v2-sections
Open

Nav sections: independent sidebar islands and dynamic top bar#3133
theletterf wants to merge 29 commits into
nav-v2from
nav-v2-sections

Conversation

@theletterf
Copy link
Copy Markdown
Member

@theletterf theletterf commented Apr 16, 2026

Summary

  • Adds section: and island: item types in navigation-v2.yml that create independent nav trees ("nav islands"). Each section owns its own sidebar HTML — pages in one section never include another section's nav links in the DOM.
  • The secondary nav bar is now data-driven from the nav-v2 file instead of hardcoded. Sections appear as left-aligned, compact tabs (55px bar height). Isolated sections (isolated: true) do not appear in the top bar.
  • Per-section sidebar caching in GlobalNavigationHtmlWriter replaces the single "nav-v2" blob — each section's sidebar is rendered and cached independently.
  • External URLs in section url: fields open in a new tab with a ↗ indicator to signal users they're leaving elastic.co/docs.
  • Nav islands (island: item type) are intra-section subtrees that get their own focused sidebar when entered, with a back arrow pointing to the parent section. Island detection uses toc root identity (nav ownership model), not URL matching, so it works across all path prefixes.
  • Section root pages skip current-page highlighting in the sidebar and auto-expand top-level folders for discoverability.
  • The back arrow for top-level isolated sections is intentionally not implemented — the UX for exiting a top-level island is still under design review.

Tab ordering

Tabs follow a task-flow logic — building tabs grouped together, situational tabs at the end:

Guides | APIs ↗ | Reference | Troubleshoot | Release notes

Sections (top bar tabs)

Section Preview URL
Guides (full V2 tree) https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/
APIs https://www.elastic.co/docs/api (external, opens in new tab)
Reference https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/reference/
Troubleshoot https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/troubleshoot/
Release notes https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/release-notes/

Isolated sections (not in top bar)

Section Preview URL
Extension points https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/extend/

Nav islands (intra-section, with back arrow)

Island Parent Preview URL
Account and preferences Guides https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3133/cloud-account

Note: Logstash plugins and versioned plugins islands are configured but use logstash-docs-md (a private repo), so they are not accessible in PR previews. Test locally with dotnet run --project src/tooling/docs-builder -- assembler build && dotnet run --project src/tooling/docs-builder -- assembler servehttp://localhost:4000/docs/reference/logstash/plugins/

YAML format

nav:
  - section: Guides            # top bar tab, owns full sidebar
    url: /
    children:
      - label: Elasticsearch fundamentals
        children: [...]
      - island: Account and preferences   # focused sidebar + back arrow
        toc: docs-content://cloud-account

  - section: APIs              # external link, new tab with ↗
    url: https://www.elastic.co/docs/api

  - section: Reference         # top bar tab, own sidebar
    url: /reference/
    children:
      - toc: docs-content://reference
      - island: Logstash plugins          # focused sidebar + back arrow
        toc: logstash-docs-md://lsr

  - section: Troubleshoot      # top bar tab, own sidebar
    url: /troubleshoot/
    children:
      - toc: docs-content://troubleshoot

  - section: Release notes     # top bar tab, own sidebar
    url: /release-notes/
    children:
      - toc: docs-content://release-notes/intro

  - section: Extension points  # isolated: not in top bar
    url: /extend/
    isolated: true
    children:
      - toc: docs-content://extend

🤖 Generated with Claude Code

theletterf and others added 6 commits April 16, 2026 19:08
Introduces the `section:` YAML item type in navigation-v2.yml. Each
section owns an independent sidebar tree and optionally appears as a
tab in the secondary nav bar. Sections marked `isolated: true` render
with a back arrow instead of a top bar tab.

Key changes:
- SectionNavV2Item record + YAML parsing in NavV2FileYamlConverter
- SectionNavigationNode nav type + NavigationSection data carrier
- SiteNavigationV2 builds sections, URL-to-section lookup
- GlobalNavigationHtmlWriter renders per-section sidebar (cached)
- NavigationRenderResult carries section metadata
- _SecondaryNav.cshtml is now data-driven (falls back to static V1)
- _TocTree.cshtml shows back arrow for isolated sections
- PlaceholderPageWriter groups by section for per-section nav

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Converts the 4 top-level label: entries in navigation-v2.yml to the
new section: format with explicit url: fields. Each section becomes an
independent nav island with its own sidebar and top bar tab.

Sections:
- Elasticsearch fundamentals → /get-started/
- Install, deploy, and administer → /deploy-manage/deploy/
- The Elasticsearch Platform → /manage-data/ingest/
- Solutions and project types → /solutions/

Nested label: items within sections are unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…oubleshoot, Reference

Restructures navigation-v2.yml so all existing labels are children of
a single "Docs" section (full V2 tree in one sidebar). Adds Release
notes, Troubleshoot, and Reference as separate section tabs.

Secondary nav bar is now left-aligned, compact, and fully data-driven
from section metadata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…to-expand

- Wrap all V2 content in a single "Docs" section; add Release notes,
  Troubleshoot, Reference as separate section tabs
- Secondary nav: left-aligned, 55px height, restored md:text-base font
- Skip current-page highlighting on section root pages via
  data-section-url attribute (includes site prefix)
- Auto-expand top-level folders on section root pages so content is
  visible without a specific page being marked current

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ove back arrow

Adds two isolated nav sections (not shown in top bar):
- Extension points (extend + kibana/logstash/beats/elasticsearch/integrations)
- Account and preferences (cloud-account)

Removes the back arrow from isolated sections — the UX for returning
from an island is still under design review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Absolute URLs (http/https) in section url: fields render as plain
links without HTMX swap or Model.Link() prefix. Sections with no
children work as external navigation targets.

Adds "API reference" tab pointing to https://www.elastic.co/docs/api

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread config/navigation-v2.yml
Islands are subtrees within a section that get their own focused sidebar
when a user navigates into their pages. A back arrow points to the
parent section's landing page (known at build time, no history.back).

YAML format:
  - section: Reference
    url: /reference/
    children:
    - toc: docs-content://reference
    - island: Logstash plugins
      toc: logstash-docs-md://lsr

Key changes:
- IslandNavV2Item record + YAML parsing for island: key
- IslandNavigationNode wraps an existing toc node
- NavigationIsland data carrier with ParentSection reference
- SiteNavigationV2 builds island list + URL-to-island lookup
  (islands take priority over sections in URL resolution)
- GlobalNavigationHtmlWriter renders island sidebar with back arrow
- Back arrow uses HTMX navigation to parent section URL

Adds Logstash plugins and versioned plugins as islands in Reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@KOTungseth KOTungseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that Docs, Release notes, Troubleshoot, API reference, and Reference are grouped together, we need to find a solution for the Docs label.

Release notes, Troubleshoot, API reference, and Reference are content types and help users navigate to a specific kind of documentation. Docs is not a content type, but is the parent context to everything else that lives inside of Docs. By grouping Docs, Release notes, Troubleshoot, API reference, and Reference together, we have mixed together wayfinding and content-type navigation.

The cleanest fix right now is to handle the "back to landing page" behavior through a separate, persistent element, like a logo or a breadcrumb. That way, the secondary nav becomes a coherent, single-purpose set of content-type links and the navigation to the landing page exists independently.

We could also change the Docs label. Something like Home or Overview signals intent a bit more clearly than Docs, through is still doesn't fully resolve the category mismatch.

Comment thread config/navigation-v2.yml Outdated
Moves Account and preferences from a top-level isolated section to an
island: entry under "Deployment and administration tools" in the Docs
section. This gives it:
- An entry point visible in the main Docs sidebar
- A back arrow pointing to the Docs section root (via the existing
  island mechanism)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The island's toc root URL was not being collected in the URL-to-island
lookup, so navigating to the root page (e.g. /cloud-account/) fell
through to the section lookup and showed the full Docs sidebar instead
of the island sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atching

URL-based island lookup breaks across path prefixes (dev vs preview vs
production). The nav system already knows which toc root owns the
current page via currentRootNavigation — use that identity to resolve
islands instead.

Replaces _urlToIsland dictionary with _tocRootToIsland keyed by the
toc root's Id. GetIslandForTocRoot takes the root navigation item
directly, matching by nav ownership rather than URL strings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Guides better signals task-based narrative content alongside the
content-type tabs. APIs is shorter and eliminates the repetition
with Reference.

Tabs: Guides | Release notes | Troubleshoot | APIs ↗ | Reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Guides → APIs → Reference → Troubleshoot → Release notes

Groups building tabs together, situational tabs at the end.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous label 'Build search queries with APIs and query languages
and search templates' wrapped to three lines in the sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@theletterf
Copy link
Copy Markdown
Member Author

@Mpdreamz Right now we have islands: as navs that have a parent in a current nav but lead to a separate nav, and sections that have isolated: true and are effectively parentless. I feel something is not quite elegant with this solution...

Takes nav-v2's refined navigation content and nests it inside the
`section: Guides` wrapper introduced by nav-v2-sections, preserving
the sections-based structure (APIs, Reference, Troubleshoot, etc.).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: GPT-5.5 <noreply@openai.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	config/navigation-v2.yml
#	src/Elastic.Documentation.Site/Navigation/NavigationViewModel.cs
Merge 3a208ff (Merge origin/nav-v2 into nav-v2-sections, May 8)
resolved the config/navigation-v2.yml conflict by taking the nav-v2
side wholesale, which has no section: or island: keys. That wiped out
seven section/island entries on this branch and broke the islands
feature this PR introduces.

Most visibly: /extend no longer renders as an isolated island and has
no back arrow, because section: Extension points (isolated: true) was
deleted from the YAML.

Restores the section/island structure by porting from demo/findability
(which preserved it through the hub-pages merge chain) and strips the
hub-pages-only section: Products block. NavigationViewModel.cs already
had its conflict resolved correctly during the merge, so no C# changes
are needed.

Sections restored:
- section: Guides (top-level wrapper around all main content)
- section: APIs (external URL to bump.sh)
- section: Reference, with island: Logstash plugins and
  island: Logstash versioned plugins
- section: Release notes
- section: Troubleshoot
- section: Extension points (isolated: true) — fixes /extend

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Island lookup keyed off currentRootNavigation.Id, which always returns
the outermost toc root. Islands that wrap a nested toc (where the page's
NavigationRoot is the enclosing toc, not the wrapped toc) never matched
and were rendered as part of their parent section instead — missing the
focused sidebar and back arrow.

For example, navigation.yml nests logstash-docs-md://lsr inside
docs-content://reference, so /reference/logstash/plugins pages have
currentRootNavigation.Id = the Reference root. The lsr-keyed entry in
_tocRootToIsland was never found, and the page rendered as a Reference
section page with no back arrow.

Replace GetIslandForTocRoot with GetIslandForNavigationItem, which walks
up the page's Parent chain and returns the first ancestor whose Id is
registered as an island. Update GlobalNavigationHtmlWriter to use the
current page item instead of its outermost root.

Verified with assembler build --environment dev:
- /docs/reference/logstash/plugins/ → back arrow + island sidebar
- /docs/reference/logstash/plugins/plugins-codecs-rubydebug/ → back arrow
- /docs/reference/logstash/versioned-plugins/ → back arrow + island sidebar
- /docs/extend/ → isolated section sidebar, no back arrow (unchanged)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… tools

cloud-account is a top-level toc in docs-content (9 pages on user
account/preferences settings, project: "Cloud account") and is wired
in V1 navigation.yml as a top-level toc, but had no entry in V2 —
pages rendered with the default Guides sidebar and no entry point.

Add it as an island under the existing "Deployment and administration
tools" group inside the "Install, deploy, and administer" label,
following the prior design intent from 1e4da5a. Users get a focused
sidebar and back arrow when in account pages, and the entry point is
visible in the main Guides sidebar.

Verified with assembler build --environment dev:
- Build logs "Rendering V2 island navigation: Account and preferences"
- /docs/cloud-account/ now shows back-arrow SVG + island sidebar

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ebar

The body has hx-boost="true", so clicking an island entry-point from
its parent section's sidebar gets intercepted by HTMX. Island links
used the default nav swap (#content-container,#toc-nav), which updates
the page content + right-hand TOC but leaves the left-hand sidebar on
the parent section's tree.

Result: clicking "Account and preferences" from the Guides sidebar
took users to /cloud-account/ with the Guides sidebar still showing —
the island appeared "not to open" even though a hard refresh would
render the island view correctly.

Add an IslandNavigationNode branch in _TocTreeNavV2.cshtml that uses
hx-select-oob=#main-container,#secondary-nav (the same swap as section
tabs and the island's own back arrow), and propagate an IsIslandSubtree
flag down so the island's descendants rendered inline in the parent
sidebar also use the full-chrome swap.

Once inside the island view, sibling navigation uses the regular
content+TOC swap (IsIslandSubtree is false in the island's own
NavigationTreeItem), so the island sidebar persists across page-to-page
navigation within the island — that part already worked.

Verified locally:
- Guides sidebar → "Account and preferences" link: full-chrome swap
- Reference sidebar → "Logstash plugins" (island entry): full-chrome
- Inside /cloud-account/, sibling page links: regular nav swap

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants