nagaozen / markdown-it-toc-done-right Goto Github PK
View Code? Open in Web Editor NEWA table of contents (TOC) plugin for Markdown-it with focus on semantic and security. Made to work gracefully with markdown-it-anchor.
License: MIT License
A table of contents (TOC) plugin for Markdown-it with focus on semantic and security. Made to work gracefully with markdown-it-anchor.
License: MIT License
What do you think adding support for a link back to the table of contents from items listed in the TOC, in order to facilitate navigation to and from. I'd be happy to draft a PR if this is something you'd be interested in. Thanks!
Just popping in to say "well done" on this plugin. Best one I've found by far.
I know that it is an uncommon event, but I noticed that if you enter two or more headings of the same level with the same title one after another, only the first one will appear in the TOC.
# Title
text
## Section
example
### subSection
text
### subSection
text
# else
In that case only the first h3 heading will appear.
Hi,
it is my experience that the sample code given in the "Cherry on top" paragraph doesn't work correctly if there are lists in the page before the TOC (if you have say 3 lists before the TOC, numbering in the TOC starts at 3). I think this is related to the fact that "list-item" refers to the "The Implicit list-item Counter"
I changed the sample code to instantiating its own counter ("list-item-toc"), and got it to work:
.table-of-contents ol { counter-reset: list-item-toc; }
.table-of-contents li { display: block; counter-increment: list-item-toc; }
.table-of-contents li:before { content: counters(list-item-toc,'.') ' '; }
Thanks for markdown-it-toc-done-right, and happy new year - feliz ano novo
When including a TOC on a page, it can happen that this is not the only nav
container on a page, with the main navigation possibly being at least one other. it would be good if the plugin would include a default name for the nav element, set via aria-label, and add an option to override this. So the nav would be:
nav aria-label="Table of contents" ...
...
</nav>
or the user provided alternative if they set it.
I am using Markdown-It-TOC-Done-Right in a new Eleventy project and found it the best TOC solution, with only this little bit missing.
Thank you for considering accessibility as one of the reasons why Markdown-It-TOC-Done-Right is the better choice over others! ❤️
Issue #15 was never really addressed and I think it is still relevant. The proposed solution of using level ranges doesn't let you exclude just a single header.
Would it be possible to add the state
object, or the runtime env
, as an argument of the callback function?
I'm using markdown-it-doc-done-right
in a context (building an Eleventy site)) where I don't control the call to the markdown-it
renderer, but where I'd like to augment the passed environment with the toc AST.
I'd like to use this as a callback:
(html, ast, state) => {
if (state.env && !state.env.toc) {
state.env.toc = ast;
}
}
I can submit a PR if you’re interested!
Hi,
I was wondering if it would be possible to add an option to automatically add the table of contents at the beginning of the content. This would be nice instead of manually adding it to the beginning of everything you render.
Thanks!
Hello.
As I posted in the other issue I’m trying to fix the markdown-it-hierarchy plugin.
I switched approaches to modify the text content to add the hierarchy numbering at the core phrase but unexpectedly I’m seeing a conflict with this plugin.
I had expected the heading id attribute to be used but it looks like because I’m altering the content text this is resulting in the ahref values in the toc using the hierarchy adjusted text, breaking them.
If the id on the heading was “some-section” this is becoming “1.2-some-section” in the toc and is then mismatched with the href on the heading that is/was added to the heading by the anchor plugin.
I’d like my plugin not to conflict with this or any other plugin but I’m not sure what I should be doing differently. Should I not be updating the content during the core phase and do it in another phase? Inserting tags instead? Should this plugin be using the id attribute of the headers instead of recreating it from the text? (I assume this may be due to supporting the anchor plugin running either before or after this plugin, if before then there wouldn’t yet be id attributes)
Input:
${toc}
## Foo
##### Bar
abc
## BOOM
Output:
TypeError: Cannot set property 'BOOM' of undefined
at headings_ast (/home/ilyaigpetrov/Repos/sl-sites/node_modules/markdown-it-toc-done-right/index.js:117:31)
at Object.md.renderer.rules.toc_body (/home/ilyaigpetrov/Repos/sl-sites/node_modules/markdown-it-toc-done-right/index.js:72:20)
at Renderer.render (/home/ilyaigpetrov/Repos/sl-sites/node_modules/markdown-it/lib/renderer.js:326:38)
at MarkdownIt.render (/home/ilyaigpetrov/Repos/sl-sites/node_modules/markdown-it/lib/index.js:543:24)
at /home/ilyaigpetrov/Repos/sl-sites/node_modules/metalsmith-markdownit/lib/index.js:75:28
at Array.forEach (<anonymous>)
at /home/ilyaigpetrov/Repos/sl-sites/node_modules/metalsmith-markdownit/lib/index.js:71:28
at Array.forEach (<anonymous>)
at Ware.plugin (/home/ilyaigpetrov/Repos/sl-sites/node_modules/metalsmith-markdownit/lib/index.js:59:72)
at Ware.<anonymous> (/home/ilyaigpetrov/Repos/sl-sites/node_modules/wrap-fn/index.js:45:19)
markdownit({
html: true,
linkify: true,
typographer: true,
})
.use(require('markdown-it-anchor'), {
slugify,
})
.use(require('markdown-it-toc-done-right'), {
slugify,
});
Sorry if i have missed this but I am trying to make the TOC render in a div to the side of the markdown content div and not in the document itself.
I have the TOC showing using a placeholder in my markdown. it just i'd prefer to be able to specify the div that the TOC is shown in instead of being rendered as part of the document.
Is this possible? Like this
it would be convenient if the generated AST had a field to hold the slugified links. I know we can augment the AST using the callback function, but having it built-in ensures the same slugify method is used.
Example of current AST:
{
"l": 2,
"n": "My Title",
"c": []
}
Example of proposed AST:
{
"l": 2,
"n": "My Title",
"u": "#my-title",
"c": []
}
I can make a PR if you’re interested!
Hello again, I was again asked in Joplin repo to post this problem here.
Joplin version used: Windows 1.0.169
Paste/import the following test file to Joplin: testing.md.txt
Click any of the TOC links.
= Only the first TOC link ("what") works, all other TOC links don't do anything.
I didn't test all non-alphanumeric characters, but testing few common ones seem to suggest that only alphanumeric characters in TOC links work.
I would like a table of contents creation for the following 4 cases:
[toc]
[TOC]
[[toc]]
[[TOC]]
Unfortunately the placeholder does not allow to specify a pattern, otherwise I could just use /^\[{1,2}toc\]{1,2}/im
.
Any chance you could allow the use of a regex pattern?
Is there a way to specify in the options that only certain header levels are included in the Table of Contents? For instance, if I want only H2 and H3 in the ToC, but not H4, H5, and H6?
The only thing that looks close is "level", which specifies the maximum level.
Perhaps as an enhancement, keep the existing functionality for level when a single value is passed in, but if an array is passed in, use just the levels in the array?
Some of my headings have inline HTML to italicize certain words. These tags are stripped from the heading before the TOC renders. Is it possible to retain the inline tags?
Input: # Future Tense: *will*
Expected Output: <li><a href=#future-tense-will>Future Tense: <em>will</em></a></li>
Actual Output: <li><a href=#future-tense-will>Future Tense: will</a></li>
I am migrating from using Kramdown, and wondered if there is functionality to exclude headers from the TOC?
In Kramdown...
# Header 1
## Header 2
{:.no_toc}
## Header 3
Would result in just creating the TOC with "Header 1" and "Header 3", excluding "Header 2" from the list.
Reference: https://kramdown.gettalong.org/converter/html.html#toc
Running into "TypeError: plugin.apply is not a function" with version 4.0.0.
r TypeError: plugin.apply is not a function
at MarkdownIt.push../node_modules/markdown-it/lib/index.js.MarkdownIt.use (vendors.._src_components_pages_blog__year__month__day__post.._src_components_pages_index.js:13325)
at _callee$ (._src_components_pages_blog__year__month__day__post.19e4fd7a250bcd634c5a.hot-update.js:145)
at tryCatch (commons.app.js:6771)
at Generator.invoke [as _invoke] (commons.app.js:6997)
at Generator.prototype.<computed> [as next] (commons.app.js:6823)
at asyncGeneratorStep (vendors.app.js:31)
at _next (vendors.app.js:53)
at vendors.app.js:60
at new Promise (<anonymous>)
at vendors.app.js:49
Reproducible using this repo.
environment : vuecli 3 + typescript
I'd like to add a class to give a different style just the item I clicked on.
What should I do?
Help me~
I'm getting this warning when using markdown-it@^11.0.0
in my package.json
:
warning " > [email protected]" has incorrect peer dependency "markdown-it@^10.0.0".
Are there any issues with markdown-it@^11.0.0
or could you bump the peer dependency?
valeriangalliat/markdown-it-anchor@5caf30a#diff-168726dbe96b3ce427e7fedce31bb0bc
markdown-it-toc-done-right should support uniqueSlugStartIndex
and change the default start index to 1
https://github.com/nagaozen/markdown-it-toc-done-right/blob/master/index.js#L108
I was searching for this kind of thing so that I could automatically generate a TOC for github markdown files in general, but it does not seem that it is supported right now. The only thing that shows up is ${toc}, no actual table of contents.
Is there anything that I need to do to enable this on Github or is this not supported?
I am looking for a way to exclude certain headings from the TOC.
For example I want a TOC for this md:
# Header 1
# Header 2 {no_toc}
# Header 3
I would like the resulting TOC to only include the first and third header.
I am unsure if an attribute is the best way to go, as I don't know if it is even possible for the plugin to remove it from the markdown. So it wouldn't get rendered.
Another idea would be to add a list or a callback as an option. The list would contain the headings to ignore. The callback would be called on each heading and the result would decide if this heading should be ignored.
I am also a little bit unsure about subheadings:
# Header 1
## Subheader 1.1
## Subheader 1.2
# Header 2 {no_toc}
## Subheader 2.1
## Subheader 2.2
# Header 3
I think if the second header should be excluded all it's subheadings should be excluded too.
I already saw, there was a similar Issue #15. But that got closed without a real resolution.
I am open to contributing and adding the feature myself.
FWIW: with this CSS, you get section numbers (for sections and subsections; subsubsections etc. can be supported analogously).
.table-of-contents {
counter-reset: toc-section;
}
.table-of-contents > ul {
list-style: none;
}
.table-of-contents > ul > li > a:before {
counter-increment: toc-section;
content: counter(toc-section) "\2002";
}
.table-of-contents > ul > li > a {
counter-reset: toc-subsection;
}
.table-of-contents > ul > li > ul {
list-style: none;
}
.table-of-contents > ul > li > ul > li > a:before {
counter-increment: toc-subsection;
content: counter(toc-section) "." counter(toc-subsection) "\2002";
}
Default:
1. Introduction
1. About the topic
2. Tips
2. First steps
1. Getting started
With the CSS and {listType: 'ul'}
:
1 Introduction
1.1 About the topic
2.1 Tips
2 First steps
2.1 Getting started
The plugin markdown-it-attrs
lets you set custom IDs like this:
## Some heading {#custom-id}
Alas, if I use it together with markdown-it-toc-done-right
, the custom IDs are only applied to the headings themselves, but not used in the TOC:
var md = require("markdown-it")({
html: false,
xhtmlOut: true,
typographer: true
})
.use(require('markdown-it-attrs'))
.use(require("markdown-it-anchor"), {
permalink: true,
permalinkBefore: true,
permalinkSymbol: '§'
})
.use(require("markdown-it-toc-done-right"));
var result = md.render(`
# Title
[[toc]]
## First section {#one}
## Second section {#two}
`.trim());
console.log(result);
/* Output (with a few newlines inserted):
<h1 id="title"><a class="header-anchor" href="#title">§</a> Title</h1>
<nav class="table-of-contents"><ol>
<li><a href="#title"> Title</a><ol>
<li><a href="#first-section"> First section</a></li>
<li><a href="#second-section"> Second section</a></li></ol></li></ol></nav>
<h2 id="one"><a class="header-anchor" href="#one">§</a> First section</h2>
<h2 id="two"><a class="header-anchor" href="#two">§</a> Second section</h2>
*/
I'm wondering how I might be able to go about adding the TOC in a different location from the content.
I'm using Vue/Nuxt for my website, and have a repeater for my content (some markdown, some other).
I'm hoping to be able to achieve the following:
<div v-html="$md.render('${toc}\n' + articleCombinedContent)" /> //without articleCombinedContent
<template v-for="(content, index) in article.content">
<div :key="index" v-if="article.type === 'rich-text'" v-html="$md.render('content.content')" />
<div :key="index" v-if="article.type === 'spacer'" :class="spacer" />
</template> -->
Is there a way to disable numbering? I’m working on fixing the markdown-it-hierarchy plugin and the approach that seems to make the most sense is to change that plugin to modify the header text during a core phase to add in the hierarchy text, like “1.1” or “2.”, prefixing it with the existing header text. But this means that there are duplicate numbers in the toc.
Am I missing the option to disable the numbering?
When using with vue-router hash routing, this link: http://localhost:5173/#/note/5
becomes this http://localhost:5173/#/addizione-e-sottrazione
when clicking on a toc heading, causing the page to be empty.
Hello, I was asked in Joplin repo to post this problem here.
Joplin version used: Windows 1.0.165
= Rendered view shows these TOC entries/links in incorrect order compared to the raw/md text:
Here's a screenshot from Joplin that shows the beginning of the TOC in side-by-side raw/md & rendered view:
Expected behavior: All TOC entries/links in rendered view should be in the order that they are in the raw/md text, i.e. no sorting.
when rendering a title with anchor, such as ## title with [anchor](github.com)
, the result in TOC is title with [anchor](github.com)
. Maybe we can add a option that determine whethere output []()
?
Hello,
First, thanks for the plugin. It works like a charm with markdown-it-anchor
.
However, I got a small problem...
Is it possible to generate a ToC in a build script without having [[toc]]
in my .md
files?
If yes, how the function would look like?
(This function should return the html
ToC snippet: <nav class="table-of-contents">...</nav>
)
Why I'd like to do this?
Because of my html
template, I'd like to paste html
ToC in some outside CSS div
.
Thanks a lot for your help.
Would you like to move markdown-it
from devDependencies to peerDependencies? I guess your case fits the goal of peer dependencies just well.
Hi,
Thank you for this amazing TOC generator! I was wondering if it would be possible to add a flag for optional generation of the <nav class="table-of-contents">
element.
I'm integrating markdown-it-toc-done-right into @superflycss/cli. Authors of MD documents may want to add additional classes to the nav
element. For example:
<nav class="TableOfContents u-ol-list-style-none u-background-color-white">
${toc}
</nav>
Thus this feature would give them design time / pre compile time control of the element.
Would also be really nice if we could control ol
or ul
through the name of the tag. For example:
${toc} // Default to ol
or
${tocul} renders the toc using ul
I'm looking for a way to set unique class for top-level list. In my own markup, I have different class at 2nd or deeper levels of ol/uls like below:
<nav class="containerClass">
<ul class="topListClass"> <!-- <-- An exception to linkClass option that I wish to set separately) -->
<li class="itemClass">
<a class="linkClass" href="#list-item">Top-Level List Item #1</a>
</li>
<li class="itemClass">
<a class="linkClass" href="#list-item">Top-Level List Item #1</a>
<ul class="submenuListClass"> <!-- <-- (i.e. I'd prefer to set this as default linkClass option for the rest of levels) -->
<li>...</li>
<li>...</li>
<li ...>
<a ...></a>
<ul class="submenuListClass">...</ul> <!-- <-- -->
</li>
<li>...</li>
</ul>
</li>
<li class="itemClass">
<a class="linkClass" href="#list-item">Top-Level List Item #3</a>
</li>
</ul>
</nav>
#32 was merged recently. We're using Markdown IT 11 and would like for the warning message to be gone in https://github.com/blamebutton/docmaker.
There does not appear to be a way to limit the TOC creation to a certain level of heading. For example, I don't want to create TOC entries for any H1s.
Given the peer dependency of markdown-it-anchor, I would expect that this package would respect the anchor level option, but it does not.
Expectation: The TOC package does not create entries for any headings without anchors (e.g. headings that were skipped by markdown-it-anchor)
Actual Behavior: The TOC package creates entries for all headings, even those without anchors. If the heading does not have an anchor, then the TOC package renders it as a non-functioning link.
Example:
const fs = require('fs');
const MarkdownIt = require('markdown-it');
const MdAnchor = require('markdown-it-anchor');
const MdToc = require('markdown-it-toc-done-right');
const mdString = `
# This is an H1 heading meant to be used for the {TITLE}
# Table of contents - This should not be an entry in the TOC
\${toc}
# BODY
## Section 1
foo bar
## Section 2
foobar
`;
const mdIt = new MarkdownIt({html: false, breaks: true, linkify: true,})
.use(MdAnchor, {permalink: true, permalinkBefore: true, permalinkSymbol: '', level: 2})
.use(MdToc);
const html = mdIt.render(mdString);
console.log(html);
Produces (indentation added)
<h1>This is an H1 heading meant to be used for the {TITLE}</h1>
<h1>Table of contents - This should not be an entry in the TOC</h1>
<nav class="table-of-contents">
<ol>
<li><a href="#this-is-an-h1-heading-meant-to-be-used-for-the-%7Btitle%7D">This is an H1 heading meant to be used
for the {TITLE}</a></li>
<li><a href="#table-of-contents---this-should-not-be-an-entry-in-the-toc">Table of contents - This should not be
an entry in the TOC</a></li>
<li><a href="#body">BODY</a>
<ol>
<li><a href="#section-1"> Section 1</a></li>
<li><a href="#section-2"> Section 2</a></li>
</ol>
</li>
</ol>
</nav><h1>BODY</h1>
<h2 id="section-1"><a class="header-anchor" href="#section-1" aria-hidden="true"></a> Section 1</h2>
<p>foo bar</p>
<h2 id="section-2"><a class="header-anchor" href="#section-2" aria-hidden="true"></a> Section 2</h2>
<p>foobar</p>
Adding this functionality can help us to place toc separately.
markdown.use(require("markdown-it-toc-done-right"), { tocCallback: toc => { //... } })
We are using your module in Joplin and it recently came to my attention that there's a request to only show the first X levels of headers in the toc.
I did some research and noticed that other toc implementations provide an option to set the number of levels or max depth.
Is there any chance you could add such an option as well? From a coding standpoint, it should not be too complicated to make this happen.
I would like to pass some options directly to the placeholder:
[toc level=2]
It would allow us to set different settings per note in the note taking app Joplin.
Would that be possible?
I want to get the JSON format of toc and render it in other place. Is there a way to do this?
Just like markdown-it-title does (inject title
to env
):
const md = require('markdown-it')({ typographer: true })
md.use(require('markdown-it-title'))
const env = {}
md.render('# Hello, *`world`!(c)*', env)
env.title === 'Hello, world!©'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.