【React】How to create a table of contents with highlighting

2022/08/23

Hello, I'm Nono.
I would like to show you how to create a table of contents with highlighting.
It is surprisingly easy to create it by using a library called react-scroll.

How to create a highlighted table of contents

Add react-scroll

react-scroll
https://github.com/fisshy/react-scroll

yarn add react-scroll 

for TypeScript

yarn add react-scroll @types/react-scroll

Source Code and Description

// component/Layout/SideMenu.tsx
import { Dispatch, FC, SetStateAction } from "react";
import { Link as ScrollLink } from "react-scroll";
import { menuList } from "src/utils/const";

type SideMenuProps = {
  isActiveScroll: string;
  setIsActiveScroll: Dispatch<SetStateAction<string>>;
};

const SideMenu: FC<SideMenuProps> = ({ isActiveScroll, setIsActiveScroll }) => {
  return (
    <nav>
      <ul className="list-none font-main text-gray-300">
        {menuList.map((menu) => {
          const active = isActiveScroll === menu;
          return (
            <ScrollLink
              to={menu}
              smooth
              duration={400}
              offset={-40}
              onSetActive={(id) => setIsActiveScroll(id)}
              spy={true}
              key={menu}
            >
              <li className="flex items-center transition">
                <div className={active ? "diamond mr-2" : "w-[5.5px]"}></div>
                <div
                  className={`${
                    active
                      ? "cursor-default font-bold text-light"
                      : "cursor-pointer rounded-lg px-3 hover:bg-gray-50/10"
                  } py-1.5`}
                >
                  {menu.charAt(0).toUpperCase() + menu.slice(1)} {/* Capitalize the first letter */}
                </div>
              </li>
            </ScrollLink>
          );
        })}
      </ul>
    </nav>
  );
};

export default SideMenu;


utils/const.ts
export const menuList = [
  "home",
  "about",
  "skill",
  "work",
  "blog",
  "github",
  "twitter",
  "contact",
];


// pages/index.tsx 
// ~~~~~~~~~~~~~~~~~~~~~~~ 
<Container> 
    <div className="headline-wrapper"> 
        <Headline title="About" id="about" /> //scroll to  id
    </div> 
...


About onSetActive in react-scroll

<ScrollLink
      to={menu}
      smooth
      duration={400}
      offset={-40}
      onSetActive={(id) => setIsActiveScroll(id)}
      spy={true}
      key={menu}
    > 
 </ScrollLink>

The onSetActive will pass the id of the target (the target with the id) when it passes over the top of the currently displayed screen.
For example, when the target passes the About section, it will send the id "about".
This is managed by the state with onSetActive={(id) => setIsActiveScroll(id)}
This will toggle the active table of contents each time the target passes by.
(Although quick scrolling may not be detected ^^;