Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I add permalinks to headers in kramdown?

I'm building a website with Jekyll and Github-Page written in markdown. I want to make it easy to permalink to headers, the way most online documentation does.

I want to get a URL with a hash when I click on a header. Is there an easy way to achieve this in Kramdown or in Jekyll's config?

Markdown page

#### A regular header

A regular sentence.

Ideal result

<h4 id="a-regular-header"><a href="#a-regular-header">A regular header</a></h4>
<p>A regular sentence.</p>
like image 200
Etrain Avatar asked Nov 07 '16 15:11

Etrain


3 Answers

If you want a GitHub Pages compatible way of doing this without JavaScript, you can get crazy creative with Liquid and carefully parse your rendered HTML as strings and manipulate it as such.

Or you could just use this snippet that does exactly that: https://github.com/allejo/jekyll-anchor-headings

like image 149
allejo Avatar answered Nov 13 '22 10:11

allejo


You can do this manually in the Markdown for each title:

#### [A regular header](#a-regular-header)

A regular sentence.

The downside there is the maintenance cost. Another option would be to create the links on the client side by adding this to the bottom of your chosen pages:

<script>
    var headings = document.querySelectorAll("h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]");

    for (var i = 0; i < headings.length; i++) {
        headings[i].innerHTML =
            '<a href="#' + headings[i].id + '">' +
                headings[i].innerText +
            '</a>';
    }
</script>

You could look into a plugin, modified Markdown parser or task runner like gulp.js to do this at build time if the JavaScript dependency doesn't suit your audience. You can't use these alternatives if you want GitHub Pages to build your page, but you can build locally and commit the output.

like image 8
Ross Avatar answered Nov 13 '22 10:11

Ross


You can use Jekyll plugins to override the standard behaviour. I put this in _plugins/header.rb:

class Jekyll::MarkdownHeader < Jekyll::Converters::Markdown
    def convert(content)
        super.gsub(/<h(\d) id="(.*?)">/, '<h\1 id="\2"><a href="#\2">§</a>')
    end
end

The regexp replaces all headers with an ID tag with one that also adds a link. This is not a fool-proof way to do this in a generic case (e.g. <h2 class="foo" id="x") won't work), but the Kramdown output is fairly reliable and consistent, so it should be okay. I added this with Jekyll 3.8.4 and Kramdown 1.17.0.

If you want/need a more robust solution then you can use a HTML parser. Shouldn't be that much harder.

The advantage of this is that it doesn't require JavaScript on the client side.


Or if you want to link the actual heading instead of prepending a link:

class Jekyll::MarkdownHeader < Jekyll::Converters::Markdown
  def convert(content)
    super.gsub(/<h(\d) id="(.*?)">(.*)<\/h(\d)>/, '<h\1 id="\2"><a href="#\2">\3</a></h\1>')
  end
end
like image 6
Martin Tournoij Avatar answered Nov 13 '22 10:11

Martin Tournoij