Docusaurus Rocks!
Tags: opensource, webdev, javascript, design
Published: 2023-10-29 21:35:01

This week, I looked into [Docusaurus](https://docusaurus.io/), one of the best tools to **generate** a beautiful **documentation site** in no time. Known for its simplicity and ease of use, it provides a clean and modern design, search functionality, and focuses on creating an easy to maintain documentation for developers. No wonder it has a **thriving community**.

In this post, I'll be sharing my **code reading results** for one of the features I would like to implement in my own [site-generation project](https://github.com/Amnish04/til-page-builder).

## Table of Contents
&nbsp;1. [Feature - TOC](#feature-toc)
&nbsp;2. [Reading the docs 📘](#reading-the-docs)
&nbsp;3. [Looking at the code 💻](#looking-at-the-code)
&nbsp;4. [Finding implementation for TOC](#finding-implementation-for-toc)
&nbsp;5. [Conclusion 🎇](#conclusion)

## Feature - TOC

The feature I'll be talking about is a common but a really handy utility. Apart from grouping various related documents into a comprehensive navbar on the left, every page on a **Docusaurus** generated site can be configured with **Table of Contents**. Since it allows the readers to skim through large pieces of writings, it is a must-have on any platform that publishes readings.

![Sample TOC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lg3xorvpnj00msr2aw20.png)

## Reading the docs 📘

I started my research by looking through the [official docs](https://docusaurus.io/docs/markdown-features/toc) that go through different types of TOCs and how a TOC can be configured.

The docs talked about 2 types of TOCs - the one that is always there on the right side, and an **inline version** you can have at the top.

![Inline TOC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxcqapq5e3ceiyhckfog.png)

I also noticed some interesting features, that allow users to configure their TOCs - in either the **document itself** or in the docusaurus **config file**.

![TOC Configurations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4zlgvzp44pqt9vpd143.png)

## Looking at the code 💻

After going through any docs concerning TOCs, I decided to dive into the actual code to get a sense of how I could add a similar feature to [my project](https://github.com/Amnish04/til-page-builder).

Since its way easier to inspect code in an IDE compared to Github, I forked the [repository](https://github.com/facebook/docusaurus) and cloned my copy on the system.

![Docusaurus file structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sahtcxfahreiji1x9m8o.png)

I took a quick glance at the file structure and was stunned by the project's sheer size and level of complexity. All the major **building blocks** were isolated in their own separate packages, essentially making the project a collection of smaller projects.

## Finding implementation for TOC

After randomly opening folders to get a basic idea of how everything was organized (with little success), I realized the only option was to start reading with a goal.

**1. Finding a lead**

The very first thing I had to figure out was where to start looking in the massive file structure I just witnessed. In other words, I needed a keyword that would lead me to the correct files.

This part is sometimes really easy when you have a UI to inspect at your disposal. I opened the browser tools and started looking at the TOC html.

![Inspecting TOC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kpsbc67lwnmez6l7oluv.png)

As expected, I found a class name **"tableOfContents"** that could easily lead me to the files and code I was looking for.

**2. Using the keyword to search**

Putting faith in the class name I had found, I immediately put it in my VSCode search bar to see how close I could get with it.

![Searching for class name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/en3ujjqh0hfbidb0y0t3.jpg)

And lucky me, I found exactly what I was looking for. I found all the implementation files, and even tests related to the feature in the first attempt.

**Link to tests:** https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/__tests__/options.test.ts

_The config files are in the generated project itself._

**3. Making sense of the code found**

Now it was time to dive into those files, and get an idea of how things were done.

The first thing I found was the well-designed schema for configuring the project's theme, and TOC was a part of it.

[**docusaurus/packages/docusaurus-theme-classic/src/options.ts**](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/options.ts) 
```tsx
export const DEFAULT_CONFIG: ThemeConfig = {
  colorMode: DEFAULT_COLOR_MODE_CONFIG,
  docs: DEFAULT_DOCS_CONFIG,
  metadata: [],
  prism: {
    additionalLanguages: [],
    theme: defaultPrismTheme,
    magicComments: [
      {
        className: 'theme-code-block-highlighted-line',
        line: 'highlight-next-line',
        block: {start: 'highlight-start', end: 'highlight-end'},
      },
    ],
  },
  navbar: {
    hideOnScroll: false,
    items: [],
  },
  tableOfContents: {
    minHeadingLevel: 2,
    maxHeadingLevel: 3,
  },
};
```

Not only this, I found various react components for different types of TOCs (sidebar and inline).

![TOC folders](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/804b9g8gf69vphq594zt.png)

Since I was planning to implement an inline TOC (although logic for all types would be similar only styling differs), I opened the `TOCInline` component.

[**docusaurus\packages\docusaurus-theme-classic\src\theme\TOCInline\index.tsx**](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/TOCInline/index.tsx)
![`TOCInline` component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgjpm5g28c2mjzq0q3x4.jpg)

Now that I found the **meat**, it was time to follow the arrows.

![Follow the arrows](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ud5s64opj1cohpval2s.png)


Apparenty, all different types of TOCs (sidebar, collapsible, inline) were just a **wrapper** to a more generic component containing the core TOC logic and html `TOCItems`.

[**docusaurus\packages\docusaurus-theme-classic\src\theme\TOCItems\index.tsx**](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/TOCInline/index.tsx)

```tsx
export default function TOCItems({
  toc,
  className = 'table-of-contents table-of-contents__left-border',
  linkClassName = 'table-of-contents__link',
  linkActiveClassName = undefined,
  minHeadingLevel: minHeadingLevelOption,
  maxHeadingLevel: maxHeadingLevelOption,
  ...props
}: Props): JSX.Element | null {
  const themeConfig = useThemeConfig();

  const minHeadingLevel =
    minHeadingLevelOption ?? themeConfig.tableOfContents.minHeadingLevel;
  const maxHeadingLevel =
    maxHeadingLevelOption ?? themeConfig.tableOfContents.maxHeadingLevel;

  const tocTree = useFilteredAndTreeifiedTOC({
    toc,
    minHeadingLevel,
    maxHeadingLevel,
  });

  const tocHighlightConfig: TOCHighlightConfig | undefined = useMemo(() => {
    if (linkClassName && linkActiveClassName) {
      return {
        linkClassName,
        linkActiveClassName,
        minHeadingLevel,
        maxHeadingLevel,
      };
    }
    return undefined;
  }, [linkClassName, linkActiveClassName, minHeadingLevel, maxHeadingLevel]);
  useTOCHighlight(tocHighlightConfig);

  return (
    <TOCItemTree
      toc={tocTree}
      className={className}
      linkClassName={linkClassName}
      {...props}
    />
  );
}
```

And finally, I was led to the `TOCItemsTree` component which was the first piece of code that made my **jaws drop**.

[**docusaurus\packages\docusaurus-theme-classic\src\theme\TOCItems\Tree.tsx**](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/TOCItems/Tree.tsx)
![TOCItemsTree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdm1svs9h8utig0ovmpm.png)

**A recursive component!**

<img width="100%" style="width:100%" src="https://media.giphy.com/media/PqcIFm93VxA8o/giphy.gif">

At first, I couldn't belive what I saw. I always knew these **tree**views and TOCs should have a tree data structure under the hood, but never thought the UI was also done in a tree style recusrive fashion. This was the most interesting thing I had found so far in Docusaurus, and I am glad to pick this feature.

Another interseting thing I found was the consistent use of [**clsx**](https://www.npmjs.com/package/clsx) library throughout the codebase.

![Clsx in code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2baxep8rox5sv19m0qhm.jpg)

I had never heard of this library before, but on a quick **chat** with the one and only - **Chat**GPT, I found that it was one of the libraries I was always looking for.

![Clsx Explanation by chatgpt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6un5vw4y0cp90xh9b0pm.jpg)

I learnt React in my college's [web422](https://webprogrammingforappsandservices.sdds.ca/) course, which was not long ago, and always wondered if there was a better way to add customized classnames in the jsx.

I have a lot of experience with Angular from my coop, and that framework has multiple powerfull strategies to configure styles/classes - [NgStyle](https://angular.io/api/common/NgStyle), [NgClass](https://angular.io/api/common/NgClass), and [interpolation](https://angular.io/guide/interpolation)  to name a few.

[Angular is better than React](https://dev.to/polterguy/angular-is-almost-always-better-than-react-300k), change my mind in comments!

**PS:** Just my opinion, both are great technologies. And everyone might have different favourites.
Here's an article for a neutral comparison.
[Angular vs React: Which One to Choose for Your App](https://www.freecodecamp.org/news/angular-vs-react-what-to-choose-for-your-app-2/)

But anyways, finding something powerfull for this purpose in React was really nice - more weapons in my arsenal now.

## Conclusion 🎇

And that is a summary of my findings when looking into docusaurus' code for ideas and inspiration. I learnt about various unexpected concepts/tools like **recursive components**, clsx library and some ideas to organize projects.

I'll be following up with a post soon, about how I add this feature to my own project.

In the meantime, **stay tuned!**