AfzGit1 downloadsMakes embedded notes seamless: shifts their headings, integrates them into the Outline view, and adds optional embed appearance controls.
Seamless Note Embed makes notes you embed in Obsidian feel like part of the note you are reading. It moves their headings to the right level, adds them to the Outline, and can hide extra embed controls. The embedded note itself is never changed.
![[note#Heading]], and headings on the same line as the embed.Given apple.md:
# apple 1
## apple 2
### apple 3
and fruits.md:
# fruits 1
![[apple.md]]
## fruits 2
![[orange.md]]
Obsidian normally renders the embedded headings at their original levels:
# fruits 1
# apple 1
## apple 2
### apple 3
## fruits 2
# orange 1
## orange 2
With this plugin, the embed is treated as part of the parent heading's section:
# fruits 1
## apple 1
### apple 2
#### apple 3
## fruits 2
### orange 1
#### orange 2
In other words, every heading inside an embed is shifted by the level of the nearest heading above the embed in the containing note. An embed with no heading above it is left at its original levels. Nested embeds are cumulative as you go deeper.
Running Outline: Show outline shows the note's own headings and the headings contributed by its embeds, indented under the correct parent.
Clicking an embedded heading in the outline navigates to the embed. Once the note is rendered, the plugin also scrolls to the exact shifted heading. Section embeds such as ![[note#Heading]] work as expected; block embeds (![[note#^block]]) do not add headings.
Quiet Outline and Subtle TOC also show the embedded headings. The plugin exposes the shifted headings through Obsidian's in-memory metadata cache, so metadata-cache-based outline plugins see them without any change to your notes. Clicking one navigates to the embed and then scrolls to the exact rendered heading.
Navigation is handled generically rather than per plugin. Embedded headings receive unique virtual line and offset values in the metadata cache, and a bridge translates those values through Obsidian's normal editor, preview, subpath-link, and CodeMirror APIs. That covers outline plugins, heading search commands such as Another Quick Switcher's Header search in file, and ordinary links to an embedded heading.
Quiet Outline's context menu and drag handling are disabled for embedded headings. Those entries point at the embed line in the parent note, so editing or moving them would change the embed link instead of the embedded note.
Other plugins that read metadataCache.getFileCache(file).headings will generally show the embedded headings too, and plugins that navigate through the common APIs above should land on the exact heading. A plugin that bypasses all of them may still stop at the embed line.
When the plugin is available in the Obsidian Community directory, install it from Settings → Community plugins → Browse and search for Seamless Note Embed.
Download main.js, manifest.json, and styles.css from the latest GitHub release, then place them in:
<vault>/.obsidian/plugins/seamless-note-embed/
├── main.js
├── manifest.json
└── styles.css
Enable Seamless Note Embed in Settings → Community plugins. The plugin folder uses the plugin ID, seamless-note-embed.
npm ci
npm run build
Copy the generated main.js, manifest.json, and styles.css into the plugin folder shown above. The build output is intentionally not committed to the repository; the release workflow builds it from source.
The command palette also has these commands:
On Obsidian 1.13 and later, every setting is searchable from Obsidian's settings search.
While plugin features are enabled, these optional CSS-only settings work independently of heading shifting and are all off by default:
The line, indentation, filename, scrollbar, open-note button, and height-limit rules are scoped to notes in Reading View and Live Preview; justification applies to Reading View. Hover previews are deliberately excluded, so Ctrl-hovering a link keeps its normal indentation, filename, scrollbar, open-note button, height limit, and left line. These settings are also carried into PDFs created with Export to PDF. If you previously used CSS snippets for these effects, disable them; a broad snippet such as .markdown-embed-content .markdown-preview-view { padding-left: 0 } will still affect hover previews.
<h1>–<h6> elements inside that embed to their shifted levels.For the Outline view, the plugin builds the same hierarchy from Obsidian's metadata cache: the note's own headings plus the headings of each embedded note, shifted recursively. It then augments the core Outline view's heading list. The Outline's existing rendering, search, folding, and navigation are reused; no separate sidebar is added.
For third-party plugins, the same virtual headings are returned through a wrapped metadataCache.getFileCache. The wrapper is transparent to this plugin's own code, which always reads the real cache, so embedded headings are never counted twice. Each embedded heading gets a unique fractional line and a virtual offset, which preserve outline order and give offset-based navigation a stable token. A navigation bridge maps those tokens back to the embed's real line and then scrolls to the rendered heading. Turning off heading shifting keeps the wrapper and outline entries active but leaves embedded headings at their original levels. Turning off plugin features removes the appearance classes, restores normal heading levels, and stops the navigation, outline, and third-party patches.
In Reading View, Obsidian can virtualize the heading above an embed out of the DOM while the embed itself is still rendered. The plugin therefore reads heading positions and embed source lines from the preview renderer's section list, so a virtualized parent heading still shifts the embed correctly.
In Live Preview, the parent note's headings are CodeMirror lines rather than <h1> tags, and long notes are virtualized. The plugin therefore reads heading positions from the editor's current source and matches each rendered embed to its source position, so off-screen embeds do not disturb the outline order.
No note files are written to. Only the rendered DOM, the in-memory outline list, and a temporary in-memory metadata-cache view are changed. The plugin's own settings are stored in its data.json, as usual.
h6; HTML has no h7.The plugin does not collect telemetry, make network requests, or modify your notes. All work happens in memory and in the rendered DOM; the only file it writes is its own settings file, data.json.
npm ci
npm run dev # rebuild on change
npm run check # TypeScript type check
npm run lint # official Obsidian plugin lint rules
npm test # heading algorithm and DOM tests
npm run build # type check and production bundle
Node.js 20.19+, 22.13+, or 24+ is required by the lint stack. Version bumps use npm version patch|minor|major, which updates manifest.json and versions.json through version-bump.mjs.
See docs/ARCHITECTURE.md for the internals and docs/DEVELOPMENT.md for the development, testing, and release workflow.
MIT