Anchors for headings in MDX

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

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>;

Override heading component

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

// ./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;
Anchor demo — show on hover
Anchor demo — show on hover
Anchor demo — show on hover
## 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”

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:

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

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 for example but I didn't want to complicate the example.

I connect humans and machines. Usually write about interfaces, digital products, and UX on tomekdev.com. Founder of checknlearn.com. A bit nerdy 🤓