Go back

July 4, 2021 | Last updated: March 9, 2021

Custom remarkJs hashtag handle for your markdown files in Nuxt 2 Content!

Learn how to create a custom handle using hast syntax tree for your Nuxt Blog and Nuxt Content Module.

Time: 3min

Introduction

Creating a custom hashtag anchor icon for my personal Nuxt 2 website was quite a journey for me. If you want to know why and how you can create your own, keep reading!!

The reason

Recently I updated my personal website with a newer version of Nuxt and I wanted to try out the content module as well and what do you know, it worked like a charm!

The content module is everything I ever wanted for my website and much, much more! The possibilities are endless and this is really exciting! Kudos to all the Nuxt team for developing such great tools and make coding such an easy and intuitive experience!

Okay, back on track. Hast, yes that's what we are talking about today. What I really wanted to achieve was to create a custom "#" (hashtag) symbol for the headers in my markdown files.

You see when you first create a content page in the content directory of nuxt every header is an a link tag where with a unique id so you can share a direct link to that section. That's handy but I wanted something more stylized. After a quick search on the web I came across this great guide by Debbie O'Brien. That's really cool and all but the thing is that since I am using Tailwind this seemed like a wasted opportunity to use the svg as an image really.

Back to Google I stumbled upon remarkjs which is the library that Nuxt content is using under the hood (and I assume many, many more..). RemarkJs is using hast syntax tree to insert nodes. That was it, I had my "Aha!" moment there. What if there was a way to customize the way that those anchors were represented by Nuxt/Content and what do you know, YES you CAN!

Thanks to this PR I was able to find a way to create a custom hashtag for my anchors 🎉

The how

If you are here just for the code, well here it is. You can add this to your nuxt.config.js file and there you have it!

  content: {
    markdown: {
      remarkAutolinkHeadings: {
        content: {
          type: 'element',
          tagName: 'span',
          properties: { className: ['icon', 'icon-link', 'inline-block'] },
          children: [
            {
              type: 'element',
              tagName: 'svg',
              properties: {
                className: ['w-8 mr-2 md:w-10'],
                fill: 'currentColor',
                viewBox: '0 0 20 20',
                xmlns: 'http://www.w3.org/2000/svg',
              },
              children: [
                {
                  type: 'element',
                  tagName: 'path',
                  properties: {
                    'fill-rule': 'evenodd',
                    d:
                      'M9.243 3.03a1 1 0 01.727 1.213L9.53 6h2.94l.56-2.243a1 1 0 111.94.486L14.53 6H17a1 1 0 110 2h-2.97l-1 4H15a1 1 0 110 2h-2.47l-.56 2.242a1 1 0 11-1.94-.485L10.47 14H7.53l-.56 2.242a1 1 0 11-1.94-.485L5.47 14H3a1 1 0 110-2h2.97l1-4H5a1 1 0 110-2h2.47l.56-2.243a1 1 0 011.213-.727zM9.03 8l-1 4h2.938l1-4H9.031z',
                    'clip-rule': 'evenodd',
                  },
                },
              ],
            },
            {
              type: 'element',
              tagName: 'span',
              properties: { className: ['sr-only'] }, // Tailwind offers this class to hide the element from regular users but still be readable from screen readers
              children: [{ type: 'text', value: 'Link to Section' }],
            },
          ],
        },
      },
    },
  },

If you are still with me (I hope you are) let's break it down so we can fully understand this. Nuxt expands on the remarkjs options which gives us the option to target the specific one that is rendered before the headings which is called remarkAutolinkHeadings. Then we simply change its content to a custom element and all we have to do is break the elements down so that they will be render as we want. For our example we render a span which holds the svg and another span for accessibility.

As you can see from the example it's fairly simply as we just break the svg into section and attributes and nest the <path> as a children with its attributes as part of the object itself. TADA!! We create a custom hashtag but the most important thing is that now this behaves the exact way we wanted to. It respects the color mode and adjust its own according to our selection (light or dark), grows or shrinks depending on the view port and we also fixed the accessibility issue we had before i.e empty anchor tag.

That was so much fun if you ask me and I hope this can help you customize and build your own Nuxt Blog or website with the Content module! If you have any comments or suggestions please let me know by commenting below (if you are reading in Dev.to) or connect with me in any of my platforms! Until the next time ✌