Plugin: Heading Navigator [v0.6.2, 2025-12-30]

NOTE: This plugin was created entirely with AI tools

Heading Navigator

A Joplin plugin that provides a simple overlay panel allowing you to navigate and filter headings in the markdown editor, inspired by sublime text's "go to symbol" function.

heading-navigator-demo

ezgif-6468e68b8b9b004e

NOTE:
This plugin only works in the markdown editor (editor view or split view). It does not work in the reading view or in the rich text editor.

Codemirror 6 only, legacy editor is not supported.

How to use

In the markdown editor, click the Heading Navigator toolbar button, or use the assigned keyboard shortcut.

NOTE:
There isn't a default keyboard shortcut, you can assign one under Tools | Options | Keyboard Shortcuts | "Go to Heading" command.

You can navigate through headings using tab key (goes to next heading), shift tab key (goes to previous heading), arrow keys, or by scrolling and selecting a heading.

When selecting a heading with the keyboard, the editor will immediately scroll to the selected heading. Hitting enter in the dialogue (or clicking somewhere else) will close the dialogue. Hitting escape will close the dialogue & return to your original scroll position.

You can filter the list of headings using the search filter at the top of the panel.

Features

  • Navigate through headings with the keyboard
  • Search filter to filter list of headings
  • Copy link to heading
  • Panel adapts to your Joplin theme
  • Adjustable panel size

Settings

The panel appearance can be customized via Settings | Heading Navigator:

  • Panel width: 240-640px (default: 320px)
    • Useful for longer heading text or smaller screens
  • Panel max height: 40-90% of editor viewport (default: 75%)
    • Prevents the panel from obscuring too much content

Settings take effect the next time the panel is opened.

Mobile Support

  • The plugin can be accessed via the toolbar icon in the editing toolbar in the markdown editor.
  • On mobile, the panel has a responsive design and appears centered with faded background.
  • On mobile, the copy link icon is hidden, and instead long-press on a heading will copy link.
9 Likes

v0.2.0

  • Feature: Adjustable panel size (in plugin settings). Width can be adjusted between 240px-640px, and height between 40% and 90% (of the editor viewport)
  • Improvement: Make search filter close button adapt to Joplin theme
  • Improvement: Better behavior when no headings are found (the panel opens displaying "no headings found" instead of nothing happening)

v0.2.1

Fix issues where scrolling could be unreliable:

  • Debounce heading previews and deferred editor to prevent race condition with scrolling editor to headings 4555897
  • Fix issue where editor sometimes didn't scroll to heading when navigating headings with keyboard 849dcee
  • Fix issue where left clicking heading sometimes didn't scroll editor to selected heading 33b6c38

v0.2.2

  • Reverted previous scrolling logic from 0.2.1 because it didn't play nicely when rich markdown plugin is rendering images in a note
  • Implemented new logic that fixes the occasional missed scrolls when tabbing through headings and doesn't cause issues with rich markdown
  • You might occasionally see a small jump when it needs to re-center a heading on a missed scroll

v0.2.3

  • Feature: Restore original scroll position when closing panel with escape key

v0.3.0

  • Massively simplified the scrolling logic.
  • Significantly improved reliability and responsiveness when scrolling through headings, less jumpiness while scrolling.
  • Remove inline markdown from headings, so heading panel only displays heading text.

NOTE: Selected headings will no longer be centered (or highlighted). The selected heading will now be at the top of the viewport (like with the Outline and DDDot plugins). This allowed me to significantly simplify the code (and I think it also feels better this way when scrolling through the headings).

Also, recent Joplin versions have an option to highlight the selected line in the markdown editor (so if you enable that you can still get the gray highlight on headings as you scroll)

v0.3.1

  • Slight tweak to fix rare case where it could scroll slightly too far, leaving the heading text cut off at the top of viewport

v0.4.0 - v0.4.1

  • Feature: Added button to copy link to heading
  • Fix: Issue with overly aggressive regex removing underscores between words in heading links

v0.4.2

  • Improve panel rendering performance

v0.4.3

  • Fix minor issues with theming and copy button management

v0.4.4

  • Performance/memory usage improvements
  • Greatly simplified panel theming by using joplin css variables instead of complex color calculations. Panel still adapts to selected joplin theme via css variables (and colors should more closely match joplin theme). Panel uses same colors as the note list for sufficient contrast with editor:

v0.4.5

  • Improve heading text extraction (using Lezer instead of regex)
  • More reliably removes inline markdown formatting, and now removes HTML tags as well

v0.4.6 - 0.4.8

  • Implement debouncing for panel search filter and improve scroll performance
  • Increase filter debounce value to fix issue where it would sometimes fail to scroll to heading when typing quickly
  • Escape html tags in link titles when copying heading link

v0.4.9

  • fix: only parse headings when panel is open
  • fix: race condition with heading filtering (would sometimes fail to scroll to correct heading when searching with the filter)
  • improvement: better default font

Full Changelog: Comparing v0.4.8...v0.4.9 · bwat47/joplin-heading-navigator · GitHub

1 Like

v0.4.10

Refined ux when using panel search filter:

  • When backspacing text in the filter, scroll to new matches if applicable instead of staying on current selected heading.
  • If you backspace all text in the filter, return to heading that was originally selected when panel was opened.

v0.5.0

  • Implemented fuzzy search using fuzzysort
  • Added bold highlighting for characters matching search

v0.5.1

  • Increased font weight for bolded search matches

v0.5.2

  • Reduce filter debounce to increase responsiveness when filtering headings. I can no longer re-create failed scrolls with lower filter debounce after the race condition fix from commit fb3f06a

Is it not allowed to post anything in this thread?

I was surprised to see no posts other than the changelog for this amazing plugin.

While I haven't reviewed every Joplin plugin, this one boasts the most sophisticated UI I've seen.

It demonstrates how to provide a polished UI beyond the panels and dialogs offered by the Joplin API.

If you're seriously considering developing a Joplin plugin, I firmly believe this plugin's code is one you absolutely must study.

Thank you so much for sharing such an amazing plugin.

2 Likes

thanks, glad you've found it useful!

I've released a new version that includes mobile support and a minor behavior change:

v0.6.0

Added mobile support:

  • On mobile, the panel has a responsive design and appears centered with faded background.

  • On mobile, the copy link icon is hidden, and instead long-press on a heading will copy link.

Other changes:

  • No longer scrolls to nearest heading when first opening the panel (if anyone preferred the previous behavior I can add an option, but I found it kind of jarring). The nearest heading will still be highlighted when opening the panel and clicking/hitting enter will scroll to it.
2 Likes

Can you publish wiki in your repository with all the research you did while developing the plugin?

I also created a plugin with Claude in Cursor and have prompted wiki pages about each part of the works.

In your screenshots, I noticed you documented your findings in Joplin, but could you make it available as wiki on GitHub?

I would love to read it and incorporate the good practices you established and also your UI works.

I created a wiki docs directory with documentation here: joplin-heading-navigator/docs at main · bwat47/joplin-heading-navigator

It's basically just a floating HTML div (vanilla typescript/DOM manipulation) that's inserted into the editor DOM and positioned above the editor with CSS

the hardest part was getting codemirror to scroll to headings with 100% reliability :smiley:

EDIT: The coding style doc from the screenshot is joplin's official coding style documentation that I use as a test case for the plugin: Coding style | Joplin

I also created docs for my rich tables plugin (which is the most complex plugin I've created): joplin-rich-tables/docs at main · bwat47/joplin-rich-tables

EDIT: I moved these from the github wiki into a /docs folder because I found the wiki being a separate repo too annoying :smiley:

1 Like