TableContents
UIComponent đ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:
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.
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.
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:
Props & API
Tất cả props của TableContents:
| Prop | Type | Default | Mô tả |
|---|---|---|---|
items* | TocItem[] | — | Danh sách các mục điều hướng |
offset | number | 80 | Khoảng cách (px) từ top khi scroll — dành cho sticky header |
title | string | 'Trên trang này' | Tiêu đề hiển thị phía trên danh sách |
className | string | — | Class CSS tùy chỉnh cho thẻ nav ngoài cùng |
Cấu trúc của TocItem:
| Prop | Type | Default | Mô tả |
|---|---|---|---|
id* | string | — | Khớp với id của phần tử DOM tương ứng |
label* | string | — | Văn bản hiển thị trong TOC |
level | 1 | 2 | 3 | 1 | Cấ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.
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".