TableContents

UI

Component điều hướng kiểu "On this page" — theo dõi section trong viewport và highlight item tương ứng.

Giới thiệu

TableContents là component điều hướng kiểu "On this page" — phổ biến trong trang tài liệu kỹ thuật như GitHub Docs, MDN, hay Tailwind CSS. Nó theo dõi section nào đang trong viewport và highlight item tương ứng trong danh sách.

Component dùng IntersectionObserver để phát hiện section đang active, và window.scrollTo với behavior: smooth để scroll mượt khi click. Không phụ thuộc thư viện ngoài, hoàn toàn headless.

Cài đặt

Component nằm trong thư mục UI và có thể import trực tiếp:

page.tsx

Cơ bản

Truyền mảng items với id khớp với thuộc tính id của các heading/section trong trang. Component tự quan sát và cập nhật trạng thái active.

page.tsx

Nâng cao

Khi layout có sticky header, truyền offset bằng chiều cao header để scroll dừng đúng vị trí. Mặc định là 80px.

page.tsx

Component hỗ trợ 3 cấp độ đầu mục thông qua trường level. Cấp 1 là heading chính, cấp 2 và 3 được thụt vào để thể hiện phân cấp:

Cách sử dụng

Kết hợp TableContents với layout hai cột — content bên trái, TOC sticky bên phải. Đây là pattern phổ biến nhất trong documentation sites:

page.tsx

Props & API

Tất cả props của TableContents:

PropTypeDefaultMô tả
items*TocItem[]Danh sách các mục điều hướng
offsetnumber80Khoảng cách (px) từ top khi scroll — dành cho sticky header
titlestring'Trên trang này'Tiêu đề hiển thị phía trên danh sách
classNamestringClass CSS tùy chỉnh cho thẻ nav ngoài cùng

Cấu trúc của TocItem:

PropTypeDefaultMô tả
id*stringKhớp với id của phần tử DOM tương ứng
label*stringVăn bản hiển thị trong TOC
level1 | 2 | 31Cấp độ heading — ảnh hưởng thụt lề và font size

Ví dụ thực tế

Component đang được dùng ngay trên trang này. Hãy scroll xuống hoặc click vào các mục bên phải để thấy hiệu ứng highlight và scroll mượt. Trên màn hình nhỏ (xl), TOC sẽ bị ẩn — chỉ hiện từ breakpoint xl (1280px) trở lên.

Accessibility

Component render một thẻ <nav> với aria-label="Table of contents", giúp screen reader nhận diện đúng. Mỗi item là một <button> với aria-current="location" khi đang active — tiêu chuẩn WAI-ARIA cho điều hướng nội trang.

Tuỳ chỉnh giao diện

TOC dùng border-l border-border cho dải dọc bên trái và -ml-px border-l-2 border-primary cho item active. Để thay màu active, override biến CSS --primary trong theme.

globals.css

Câu hỏi thường gặp

TOC không highlight đúng section?

Kiểm tra id của section khớp chính xác với id trong TocItem. Nếu section quá ngắn, IntersectionObserver có thể không kích hoạt — thêm min-h-[200px] hoặc điều chỉnh rootMargin trong hook.

Scroll không đúng vị trí?

Truyền offset bằng chiều cao thực của sticky header. Nếu dùng layout này (header 64px), set offset={64}.

Muốn TOC luôn hiện trên mobile?

Bỏ class hidden xl:block trên thẻ aside, hoặc đặt TOC vào một Drawer / Sheet kích hoạt bằng nút "Mục lục".