It would be nice to have inbuilt, within Obsidian, a Table of Contents (TOC) tool that self-upgrades / automatically upgrades, such that changes in headings are captured and rendered.
It’s disappointing that Obsidian lacks such a basic tool.
Existing plugins for this aren’t getting the job done.
I’m aware that DToC is now archived. And in its archived form, it’s not useful.
For instance, headings’ indentation and varied levels aren’t being reflected in the table of contents that it creates. As a result, when applicable, one can’t see which headings are others’ subheadings. DToC now shows all headings as being on the same level, when that’s not the case (I have Obsidian version 0.16.5, and it created this problem well before this version).
The older plugin that came before DToC isn’t dynamic and therefore cannot automatically upgrade its contents when changes are made --forcing users to waste time constantly recreating TOCs.
A plugin that (1) preserves and shows the different levels of headings within a document and (2) automatically upgrades any created TOC’s content when heading changes are made would not only be nice but crucial. MS Word even does this well.
It still doesn’t address the fact that creating TOC’s isn’t an inbuilt feature.
And why is that a big problem?
Because (1) the ability to create TOC’s is a crucial and fundamental capacity (that’s available in MS Word and many classic word processors) and (2) many Obsidian plugins undergo neglect.
For instance, this plugin “had not been updated for a long time” and is available only through BRAT.
Why not just use Dataview? It’s simple, functional, and automatically updates.
Create a toc.js file in the root of your Obsidian vault, with this contents:
// Set this to 1 if you want to include level 1 headers,
// or set it to 2 if you want to ignore level 1 headers
const startAtLevel = 2
const content = await dv.io.load(dv.current().file.path)
const toc = content.match(new RegExp(`^#{${startAtLevel},} \\S.*`, 'mg'))
.map(heading => {
const [_, level, text] = heading.match(/^(#+) (.+)$/)
const link = dv.current().file.path + '#' + text
return '\t'.repeat(level.length - startAtLevel) + `1. [[${link}|${text}]]`
})
dv.header(2, 'Table of contents')
dv.paragraph(toc.join('\n'))
And then in any note which you wish to add a dynamic TOC, you just add this code:
I’m +1 on this plugin Idea. I’d love to have a Table of Contents outline that is automatically updated in my document. It’s a useful feature in other note apps and I’m glad to see it being addressed here.
And, I agree this feature is perfect for a community or core plugin.
Update
I just found the core plugin Outline and it does what I was looking for. When turned on there is a document outline / Table of Contents based on headers in the left panel. If I click on the outline heading in the panel, the cursor jumps to that position in the main window document. Perfect.
I think the updating automatically is the issue, but I just close and reopen the doc to update the outline. Thanks
Thanks for that , works nicely but i see some issues.
It only sees Header one and two. Header three is not showing.
Underlying header does not print previous header. So for example when i start a header 2 under header 1 i would expect something like 1.1 but it only prints 1
The floating Toc plugin is currently working flawlessly for me here- and it even implement that in the way i like most wich is besides the main document (much like the outline panel), so one can quickly jump to other headers no matter where they are on the page.
Thank for the css it now has the output as i like it.
And the third header is also solved. Apparently when you have one space too many the header is not seen as a header So i was have 2 Spaces in between the # and the header.
I notice the references in the toc refer to obsidian locations. Can i also refer just to the headers inside the document without refering to obsidian. I wan to be able to export the note to PDF and send this to someone that does not have my obsidian