Next.js App에서 아티클 TOC(Table of Contents) 기능 구현하기

Next.jsReactTableOfContentstocbotWebDevelopmentSEO
avatar
2025.04.02
·
5 min read

웹에서 긴 아티클을 읽을 때 목차(TOC, Table of Contents) 기능이 있으면 사용자가 원하는 내용을 빠르게 찾을 수 있습니다. 이번 글에서는 Next.js 환경에서 tocbot을 활용하여 TOC를 생성하고, 해시 네비게이션을 처리하는 방법을 단계별로 설명합니다.


1⃣ tocbot 라이브러리 설치

먼저, tocbot 라이브러리를 설치합니다.

npm install tocbot

tocbot은 문서의 헤딩 태그(h1, h2, h3 등)를 자동으로 감지하여 TOC를 생성해 주는 라이브러리입니다. 이를 활용하면 별도의 수작업 없이 목차를 자동으로 구성할 수 있습니다.


2⃣ 스타일 추가

TOC가 화면의 왼쪽에 고정되도록 styles/toc.css 파일을 생성하고 다음과 같이 작성합니다.

.toc {
  position: fixed;
  top: 100px;
  left: 20px;
  width: 250px;
}

이제 기본적인 TOC 스타일이 적용되었습니다.


3⃣ TOC 컴포넌트 구현

다음은 Contents.tsx 파일에서 TOC 기능을 구현하는 코드입니다.

import './styles/toc.css'

import { FC, useEffect, useState } from 'react'
import { HEADER_HEIGHT } from 'src/blog/components/Header'
import tocbot from 'tocbot'
import { contentSelector, headingSelector, tocSelector } from './constants'
import { makeIds } from './utils'

const Contents: FC = () => {
  const [hasTocContent, setHasTocContent] = useState(false)
  useEffect(() => {
    makeIds()

    tocbot.init({
      tocSelector,
      contentSelector,
      headingSelector,
      hasInnerContainers: true,
      headingsOffset: HEADER_HEIGHT,
      scrollSmoothOffset: -HEADER_HEIGHT,
    })

    const tocElement = document.querySelector(tocSelector)
    if (tocElement && tocElement.innerHTML.trim() !== '') {
      setHasTocContent(true)
    }

    try {
      const hash = decodeURI(window.location.hash)
      if (!hash) {
        return
      }

      const element = document.getElementById(hash.slice(1))
      if (!(element instanceof HTMLElement)) {
        return
      }

      if (!('scrollRestoration' in window.history)) {
        return
      }
      window.history.scrollRestoration = 'manual'

      element.scrollIntoView()
    } catch (error) {
      console.log('Error decoding hash:', error)
    }

    return () => {
      tocbot.destroy()
      if ('scrollRestoration' in window.history) {
        window.history.scrollRestoration = 'auto'
      }
    }
  }, [])

  return (
    <div
      style={{ opacity: hasTocContent ? 1 : 0 }}
      className="grid gap-2 transition-opacity"
    >
      <div className="toc" />
    </div>
  )
}

export default Contents

4️⃣ 주요 구현 사항 단계별 설명

tocbot 초기화 및 TOC 생성

tocbot.init({
  tocSelector,
  contentSelector,
  headingSelector,
  hasInnerContainers: true,
  headingsOffset: HEADER_HEIGHT,
  scrollSmoothOffset: -HEADER_HEIGHT,
})
  • tocSelector: TOC가 들어갈 컨테이너

  • contentSelector: 문서 본문

  • headingSelector: TOC에 포함할 헤딩 태그들

  • headingsOffset: 스크롤 위치 보정 (고정 헤더 고려)

  • scrollSmoothOffset: 부드러운 스크롤 이동 보정

② TOC가 존재하는지 확인

const tocElement = document.querySelector(tocSelector)
if (tocElement && tocElement.innerHTML.trim() !== '') {
  setHasTocContent(true)
}

TOC가 비어있지 않다면 화면에 표시합니다.

scrollRestoration이란?

Next.js에서는 브라우저의 기본 스크롤 복원 기능이 활성화되어 있습니다. 즉, 사용자가 페이지를 새로고침하면 마지막 스크롤 위치를 기억하고 복원합니다.

하지만 TOC 기능을 구현할 때, 페이지가 새로고침될 때 특정 섹션으로 이동해야 하는데, 이 기능이 방해가 됩니다. 따라서 이 기능을 비활성화해야 합니다.

if ('scrollRestoration' in window.history) {
  window.history.scrollRestoration = 'manual'
}

이렇게 설정하면 브라우저는 이전 스크롤 위치를 자동으로 복원하지 않으며, 우리가 지정한 위치로 이동할 수 있습니다.

④ 기존 스크롤 복원 기능 해제

return () => {
  tocbot.destroy()
  if ('scrollRestoration' in window.history) {
    window.history.scrollRestoration = 'auto'
  }
}

컴포넌트가 언마운트될 때 tocbot을 해제하고, Next.js의 기본 스크롤 동작을 복구합니다.


🎯 결론

이제 Next.js에서 tocbot을 활용하여 아티클 TOC 기능을 완벽하게 구현할 수 있습니다.

주요 기능

  • TOC 자동 생성 및 표시

  • 클릭 시 부드러운 스크롤 이동

  • 새로고침 후에도 TOC 위치 유지

  • Next.js의 스크롤 복원 문제 해결

이제 여러분의 블로그나 문서 프로젝트에 쉽게 적용해 보세요! 🚀







- 컬렉션 아티클