Rushing Labs

Header Components

Ref: https://tomekdev.com/posts/anchors-for-headings-in-mdx

Reasoning

I wanted to be able to link to individual sections with the blog articles. This meant being able to link to specific sections within the Markdown content. Traditionally, you would do that as described in this Markdown syntax reference, below. However, for some reason this wasn't working with the MDX syntax, and I'm not too sure what the issue was but figured it had something to do with the hyperlinked text needing to pass through MDX -> Markdown -> HTML parsers.

 See the section on [`your-header`](#YourHeader) 

Solution

So, writing a new MDX component it is!

Location: .\components\content-helpers\anchors.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}>
            {children}
            <a href={link} className="anchor-link">
                §
            </a>
        </h2>
    )
}
export default H2;

And then let's repeat that for <h2>, <h3>, and <h4>...

import styles from './anchors.module.css';
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} style={{ position: `relative` }}>
            {children}
            <a href={link} className={styles.anchor}>
                §
            </a>
        </h2>
    )
}
const H3 = ({ children }) => {
    const anchor = getAnchor(children);
    const link = `#${anchor}`;
    return (
        <h3 id={anchor}>
            {children}
            <a href={link} className="anchor-link">
                §
            </a>
        </h3>
    )
}
const H4 = ({ children }) => {
    const anchor = getAnchor(children);
    const link = `#${anchor}`;
    return (
        <h4 id={anchor}>
            {children}
            <a href={link} className="anchor-link">
                §
            </a>
        </h4>
    )
}
export { H2, H3, H4 };

Notice we're now importing some styles, and we no longer have a default export but a collection of named exports: export { H2, H3, H4 }.

And here's our styles.

Location: .\components\content-helpers\anchors.module.css

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

We can then patch this into the necessary parts of the MDX provider for the website.

  • .\pages\blog\[year]\[id].js
  • .\pages\docs\[section]\[id].js
  • .\pages\projects\[project]\[id].js
import { H2, H3, H4 } from '../../../components/content-helpers/anchors';
/* ...removed for brevity...*/
<MDXRemote {...mdx} components={{ 
    h2: H2,
    h3: H3,
    h4: H4,
    Button, 
    Image, 
    Link, 
    CenteredImage, 
    SyntaxHighlighter, 
    MyDocHighlighter,
    TikTok
}} />