Go back

On sidenotes implementation

2025-11-04 01:10 - 2025-11-07 04:39 (f0a07e8), 5 min read
#web

Table of Contents

This week, I finally implemented my sidenotes on this blog. It was a work in progress for about 1 year, from the first attempt at implementation until reaching a decent solution.

All the implementation was based on a “philosophy” of what I believe is the best way to present a blog to the reader and organize how it can be read. It was mainly inspired by Sidenotes in Web Design, by GwernAs a showcase, this is how it will look with the new implementation..

I think that, specifically for blog posts, sidenotes can be more useful than footnotes/endnotes, which, at least for me, bring a bad user experience, where you need to go back and forth between the anchored sections of your text to have the full context of something that has been written.

On the other hand, sidenotes help give an easy stream of text with the full context of a given scope, considering that all sidenotes are close to their paragraphs. It’s easier to follow a text with your eye when you have all the sections together, without the overhead of the navigation.

Core philosophies

Focus on being web-friendly. As one of the core points of my implementation, I approached it as much as possible, following some web-friendly concepts. What does that mean? Ideally, the entire implementation should be JavaScript-free.

In my current implementation, sadly, this isn’t 100% true (maybe it never will be), because I had to make some trade-offs to improve the user experience for sidenote usage. But all the core implementation is based on Tufte CSS.

Also, following it, I added some approaches most inspired by the way Gwern did their sidenotes: anchoring each sidenote. Then you can easily click on any sidenote and use it as the anchor for that page. I really like anchoring.

And for mobile devices, it shows, close to the text that each sidenote refers to, whether it can be readily displayed or not. Try accessing these on a mobile device and check this behavior. It’s really cool.

Avoid introducing new stuff. I want to be as compatible as possible with the current footnote implementation in markdown, without adding any new syntax or a different approach to managing text. In the end, this should be just markdown, and I intend to keep it that way going forward, so I wouldn’t like to use MDX, for example.

With that in mind, I narrowed my options on how to approach it. But the main reason for this decision is to ensure that all my notes can be easily ported between platforms and that I can write them wherever I am. Because, as I said, it’s just a bunch of simple markdown notes.

Implementation

Specifically, the implementation is split into two parts: the markdown plugins and the styles and UX improvements.

The markdown plugins are being added to override the expected behavior of the known footnotes approach and replace it with our own sidenotes implementation. They are composed of these two plugins: remarkPluginSidenotes.ts and rehypePluginSidenotes.ts.

Talking about them, the first one handles all the boring jobs: traversing the AST, extracting the footnote, removing unnecessary nodes, and injecting new nodes.

The second one retrieves the HTML result and applies specific replacements to manage it. It ensures the expected attributes are added to the <label> and <span> tags. These will be needed to guarantee that the anchoring of the elements works as expected.

Now, the rest of the implementation is available here. It’s doing a lot of things here, but explaining in a high-level way:

  • Inject all needed styles for the sidenotesAs mentioned before, all this stylization is based on Tufte CSS. Yes, I’m using a sidenote just because it’s cool..
  • Add some stylizations, just to be cute. Similar to how Gwern did on their blog. A bidirectional hover linking both the sidenote number and the sidenote container, per se. When you hover or click on each sidenote, it will have a different style.
  • Add the logic to ensure the page loads to the correct anchor element, if it exists.

That’s where all the JavaScript I mentioned before appears. Sadly, some of the things I’d like to do with my sidenotes aren’t achievable only using CSS, so I had to use JS in part of the implementation.

Next steps

There’s a lot of cool stuff that I could do using sidenotes. Definitely, there are some improvements and better experiences that can be done in future iterations, which will be what I’ll be looking to.

For example, a friend of mine suggested that, on a mobile device, instead of showing the sidenote in the middle of the following line, right after the original reference, it could be a pop-up. It’s something interesting that I’ll be working on for future improvement.

Also, I’d like to render richer Markdown and other content within the sidenotes. It’s limited in what I can do, mainly because of how it’s being parsed, but that’s another improvement I’ll be working on.

This is a bit about how I did the first implementation of my blog’s sidenote. I hope it brings some cool ideas and flourishes creative ideas you can use on your own blog.