Anchors for headings in MDX
Tags: mdx, javascript
Published: 2021-02-09 20:47:38

---
title: Anchors for headings in MDX
published: true
tags: MDX, JavaScript
canonical_url: https://tomekdev.com/posts/anchors-for-headings-in-mdx
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/q6ugqw6xy7rhuedq7fye.png
---

_This post was originally published on https://tomekdev.com/posts/anchors-for-headings-in-mdx. What you see as GIF here is interactive there._ ✌️

----

How to add anchors to headings in MDX? It's surprisingly easy to do. I assume you are already familiar with MDX so somewhere in your code you should have a blog page layout component that uses `<MDXProvider>`, like that:

```jsx
<MDXProvider>{children}</MDXProvider>
```

MDX consists of components itself. So if there is a code like `this` then the interpreter changes the inner value (children) into the same content but wrapped with `<code></code>`.

The same applies to all the headings, lists, paragraphs, etc. Our job is to override the headings. We can do it by passing `components` hash and specifying a replacement.

```jsx
import H2 from './MyCustomMDX/H2';
import H3 from './MyCustomMDX/H3';
import H4 from './MyCustomMDX/H4';

// ...

<MDXProvider
  components={{
    h2: H2,
    h3: H3,
    h4: H4,
  }}
>
  {children}
</MDXProvider>;
```

Please notice that we are not going to add an anchor to the `<h1>` tag. It doesn't make sense in my opinion. `<h1>` is like a summary of the whole page. The URL that links to it is the direct link to the post. Anchors should be used to specific parts of a post (to a section).

## Override heading component

The override for `<h2>` that shows an anchor when the mouse is over the text could look like this:

```jsx
// ./MyCustomMDX/H2.js

function getAnchor(text) {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9]/g, '')
    .replace(/[]/g, '-');
}

const H2 = ({ children }) => {
  const anchor = getAnchor(children);
  const link = `#${anchor}`;
  return (
    <h2 id={anchor}>
      <a href={link} className="anchor-link">
        §
      </a>
      {children}
    </h2>
  );
};

export default H2;
```

Below you'll see the demo. Please notice the hover state. On the left you should see `§` sign that is also a link, representing our anchor:

![Anchor demo](https://dev-to-uploads.s3.amazonaws.com/i/z81fc678d70qyi6i2v6t.gif)
 
Let's explain a few bits. The way we use headings in Markdown is by using `#` sign, for example:

```markdown
## I'm h2 with an anchor
```

Everything that goes after `## ` is passed as a child to the `H2` component.

So the next interesting bit is done in the `getAnchor` function. Take a look at lines 3 to 8. This is what happens:

- line 5 - we convert the input to lower case → "i'm h2 with an anchor"
- line 6 - we remove all non-alphanumeric characters → "im h2 with an anchor"
- line 7 - we replace spaces with a hyphen → "im-h2-with-an-anchor"

... and voilà. We have a URL-friendly anchor 🎉

## The styling

Another important thing here is the CSS. We want to show the anchor only on hover and somewhere next to the heading itself:

```css
h2 {
  position: relative;
}

.anchor-link {
  color: #666;
  opacity: 0;
  position: absolute;
  transform: translate(-1em, -2px);
  width: 1em;
}

h2:hover .anchor-link {
  opacity: 1;
}
```

Of course, you can go crazy with your anchors ;) That one is very basic.

## Recommendation

One thing that is easy to overlook here (in my example) is using a character like `§` inside of `<h2>` tag. In this approach, **the sign will become a part of the document outline**. Which is not something we want. It's better to use an icon in SVG format but I didn't want to complicate the example.

If the simple sign is what you want then you should render `<a>` tag before or after the `<h2>`.