Skip to content

feat(web): add a heading outline beside Markdown previews - #960

Open
Matt Van Horn (mvanhorn) wants to merge 3 commits into
JetBrains:mainfrom
mvanhorn:feat/markdown-outline
Open

Matt Van Horn (mvanhorn) wants to merge 3 commits into
JetBrains:mainfrom
mvanhorn:feat/markdown-outline

Conversation

@mvanhorn

@mvanhorn Matt Van Horn (mvanhorn) commented Oct 27, 2026 •

Copy link
Copy Markdown

Problem

Long Markdown files, specs included, are hard to move around in Preview. The only options are scrolling or searching for a heading's text, and nothing shows the shape of the document while you read.

Approach

The preview builds an outline from the headings it already renders and reuses their ids, so outline links always land on the rendered heading. The outline sits beside the document. It tracks the section you're reading with an observer instead of re-rendering on scroll, and it hides itself in narrow panes and in documents with fewer than two headings.

Changes

  • New outline panel next to rendered Markdown previews, nested by heading level. Clicking an entry scrolls the preview to that heading.
  • The current section is highlighted while you scroll, and the outline updates when the file changes.
  • A show/hide toggle, remembered per client. It starts hidden in narrow panes.
  • Headings are extracted in a pure function that skips frontmatter and fenced code and handles duplicate headings and skipped levels.
  • packages/resource-renderers/SPEC.md updated. New strings added to packages/locales/en.json.

Screenshots

Before: the preview of a long Markdown file has no outline.

before

After: the heading outline sits beside the preview, with the current section highlighted.

after

Related issues

Closes #757

Checklist

  • Fast gates pass: bun run lint, bun run typecheck, bun run test
  • E2E suite passes for app-affecting changes (bun run e2e). The new e2e/markdown-outline.spec.ts passes. Locally, 4 topbar-review.spec.ts tests fail on a git push to the sample remote, which this change doesn't touch.
  • Before/after screenshots are included for frontend changes
  • Relevant SPEC.md / top-level specs updated to reflect any boundary, contract, or behavior change
  • I have read the Contributing guide and agree to the Code of Conduct

Demo

demo

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

Comment thread packages/resource-renderers/src/support/MarkdownPreview.tsx Outdated
Comment thread packages/resource-renderers/src/support/outlineHeadings.ts Outdated
Comment thread packages/resource-renderers/src/support/markdownLinks.tsx Outdated
Rendered Markdown previews list the document's headings in a collapsible
outline beside the document. Clicking an entry scrolls that heading in
the preview scroller, the current section is marked as the reader
scrolls, and the hide/show choice persists per client.
…preview

Allocate heading ids once from a GFM parse so the outline, in-document
anchors, and spliced review segments land on the same elements. Unicode
headings get a nonempty slug; existing ASCII slugs stay unchanged.
@cursor
cursor Bot force-pushed the feat/markdown-outline branch from 0780441 to 5109076 Compare October 27, 2026 22:19

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

Comment thread packages/resource-renderers/src/support/MarkdownOutline.tsx Outdated
Comment thread packages/resource-renderers/src/support/outlineHeadings.ts
Comment thread packages/resource-renderers/src/support/outlineHeadings.ts Outdated
@CommanderTvis

Iaroslav (Rick) Postovalov (CommanderTvis) commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor
  1. Chosen default position of the outline (to the left or the right) should be either justified or be configurable in settings.
  2. Outline also totally makes sense in code editor of .md file.

@mvanhorn

Copy link
Copy Markdown
Author

Thanks for looking at this.

  1. I put it on the right because that's where GitHub shows the outline for a rendered Markdown file, and it keeps the prose column anchored to the left edge the reader is already scanning. It's a weak default though, so a left/right option is reasonable. Would you rather have that as a setting in this PR, or keep this one to the preview and add the setting separately?

  2. Agreed that a .md file open in the code editor should get it too. The heading extraction (extractMarkdownOutline) is already independent of the renderer, so the editor side would mostly be wiring it to the editor's scroll position and reveal. That touches the editor surface rather than resource-renderers, so I'd suggest a separate PR for it, unless you want both here.

@CommanderTvis

Copy link
Copy Markdown
Contributor

Thanks for looking at this.

  1. I put it on the right because that's where GitHub shows the outline for a rendered Markdown file, and it keeps the prose column anchored to the left edge the reader is already scanning. It's a weak default though, so a left/right option is reasonable. Would you rather have that as a setting in this PR, or keep this one to the preview and add the setting separately?
  2. Agreed that a .md file open in the code editor should get it too. The heading extraction (extractMarkdownOutline) is already independent of the renderer, so the editor side would mostly be wiring it to the editor's scroll position and reveal. That touches the editor surface rather than resource-renderers, so I'd suggest a separate PR for it, unless you want both here.

I think that a setting makes sense.

I'm not a team member, so can't guide you on flow of PRs.

- Match spliced-segment heading ids by source line and reserve every
  document id, so a heading that only parses inside a segment (a split
  setext underline) cannot take a later heading's id.
- Reveal the active outline entry by adjusting only the list's own
  scrollTop, so an enclosing transcript never scrolls.
- Open closed <details> ancestors before scrolling to a selected heading.
- Cache heading elements and binary-search the active one at most once
  per animation frame instead of querying every heading on every scroll.
- Add a Left/Right "Markdown outline position" option to Appearance
  settings (client preference, defaults to right).
@mvanhorn

Copy link
Copy Markdown
Author

Added the setting in c755dd2. Appearance settings now has a "Markdown outline position" row with Left and Right; it defaults to Right and is stored as a client preference next to the outline's show/hide state. The editor-side outline for .md files I'll leave for a follow-up PR.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a heading outline to Markdown previews

2 participants