Build 01: Reference Link Component
On This Page
Problem
I sat down to start documenting (and publishing) my learning of the field of Process Management, and ran into a small issue.
Let's look at the code I wrote together quickly:
# Process Management Primer
## References
[1](#ref-1) - [US Bureau of Labor Statistics](https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm#:~:text=99%2C050-,Most%20software%20developers%2C%20quality%20assurance%20analysts%2C%20and%20testers%20work%20full,robotics%2C%20and%20other%20automation%20applications.)
[2](#ref-2) - [State of the Software Engineering Job Market in 2025 Part 1](https://newsletter.pragmaticengineer.com/p/state-of-the-tech-market-in-2025)Good markup for indicating what I want out of a reference section, but won't work in reality.
Essentially, what I'm doing here is marking up the idea that there should be a link pointing to an incremental reference ID and the actual reference nearby.
That's not quite correct - what should actually happen is that the incremental reference ID should contain the reference.
That's a bit awkward to write out in Markdown, but luckily we're using MDX here, so I can easily write some atomic TSX that handles that complexity.
Exploration
In this subheading, we'll go over the steps required to complete the task and the reasoning at each step.
1. Boilerplate
We can start by looking at the basic boilerplate for an idea like "collection of links":
type Reference = {
href: string;
label: string;
};
export default function References(args: { references: Reference[] }) {
return (
<div>
{args.references.map((reference, id) => {
return (
<a href={reference.href} key={`${reference.label}-${id}`}>
{reference.label}
</a>
);
})}
</div>
);
}Super basic starting point, just to pass this sign post in the story.
We create a basic Reference type - it's not validated or aggressively restricted, just promising that a reference has two specific keys (href and label), and that they are strings, which satisfy each place they appear in the markup.
The name-by-convention for React Function Components is, of course, props, but that is one more character than args so I use args. The number one cause of bugs is keystroke count, after all.
2. Incremental IDs
Pretty basic addition... I have the sensation that I'm moving a bit too slowly here, but I'm working hard to avoid writing down something like "draw the rest of the owl."
export default function References(args: { references: Reference[] }) {
return (
<div>
{args.references.map((reference, id) => {
return (
<a
id={`ref-${id}`}
href={reference.href}
key={`${reference.label}-${id}`}
>
{reference.label}
</a>
);
})}
</div>
);
}The idea here is to convert the positional index of the array of references to a guaranteed-unique string in the anchor tag's ID field.
This is the key of the component - I can just create an array of URI/Label tuples inside the MDX and get specific anchors in the footnotes of the article.
3. Integration
NextJS with MDX requires making any custom components available in ./mdx-components.tsx, a sibling to the app folder, like so:
import type { MDXComponents } from "mdx/types";
import References from "./components/custom/References";
const components: MDXComponents = {
References,
};
export function useMDXComponents(): MDXComponents {
return components;
}That enables simple markup like so:
# Process Management Primer
## References
<References references={[
{
label: "US Bureau of Labor Statistics",
href: "https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm#:~:text=99%2C050-,Most%20software%20developers%2C%20quality%20assurance%20analysts%2C%20and%20testers%20work%20full,robotics%2C%20and%20other%20automation%20applications."
},
{
label: "State of the Software ENgineering Job Market in 2025 Part 1",
href: "https://newsletter.pragmaticengineer.com/p/state-of-the-tech-market-in-2025"
}
]} />4. Considering Cleanup
We now have a node structure like this:
## References
<References references={[]} />Theoretically, we could move that h2 inside the new References component, but...
It removes our capacity for adding nearby markup. It's clearly a premature optimization - as my writing style develops and evolves, we may need to add further args to that component, but we don't know what they are right now.
So, no need for cleanup.
5. Considering Styling
Let's take a look at the currently rendered block:

Not great! Not my tempo, you know.
Key issues:
- Reference Label is over-sized compared to what a footnote should be - a signpost or clue that there is more information.
- Missing incrementer - honestly, just a structural issue on my original boilerplate.
Here's the updated styling:

And the code to make it:
type Reference = {
href: string;
label: string;
};
export default function References(args: { references: Reference[] }) {
return (
<nav>
<ul className="flex flex-col gap-2" style={{ paddingLeft: 0 }}>
{args.references.map((reference, id) => {
const displayId = id + 1;
return (
<li
className="flex flex-row gap-2 align-center text-sm"
key={`${reference.label}-${id}`}
style={{ margin: `0`, paddingLeft: `0` }}
>
<p style={{ margin: `0` }}>[{displayId}]</p>
<a
id={`ref-${id}`}
href={reference.href}
className="h-fit m-0 p-0"
>
{reference.label}
</a>
</li>
);
})}
</ul>
</nav>
);
}6. Process Summary
That last block of code is a bit of a rest-of-the-owl scenario. I'm sorry about that. We executed 3 main ideas in a single turn:
- Semantic HTML: We moved from a generic
divcomponent to well structurednav,ul, andlicomponents to indicate that the references are, in fact, a navigational component. - Display ID: We increment the positional index of the reference as Javascript arrays are zero-indexed, and most reference-counting systems are one-indexed. I have never seen a
zerothfootnote in the wild. So, while internally we can use the 0-indexed system, we want to display the 1-indexed system to users. - Inline Styling: There are default styles for most lists coming from tailwind typography plus some custom styling. That can be overwritten by applying inline styles directly to the HTML elements.
Result
Now, we have an extensible, easy way of communicating our sources.
This isn't exactly ground-breaking research, but I hope it shows how I personally approach problems.
Next Steps...?
For now, our Devex for actually referencing the resources is a bit awkward. I wonder if it's worth adding a custom component like <Ref id={0} /> to automatically insert an anchor tag that scrolls to the reference in the footnote and applies superscript styling...