feat: add sticky index to resource pages - #914
Draft
jacobvjk wants to merge 1 commit into
Draft
Conversation
Expected version change and release notes:1.16.0-dev.16 (v1.16.0-dev.15...feat-documentation-sliding-index ) (2026-08-20T12:26 UTC)Features
|
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://proud-glacier-0f640931e-914.westus2.2.azurestaticapps.net |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a reusable sticky “On this page” index to the Resource pages to improve long-page navigation and support stable section linking, per #802 (excluding Updates as specified).
Changes:
- Introduces a new
OnPageIndexcomponent that builds a TOC fromh2[id]headings and highlights the active section while scrolling. - Updates all resource pages (except
ResourcesUpdatesPage.tsx) to add stableids on top-levelh2s and mount the index in a two-column desktop layout. - Adds unit tests for
OnPageIndexplus per-page assertions that only the intended top-level sections appear in the index; extends the test environment with anIntersectionObservermock.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/test/setup.ts | Registers global mocks for IntersectionObserver and scrollIntoView and resets mock instances between tests. |
| src/test/mockIntersectionObserver.ts | Adds a controllable IntersectionObserver mock to drive scroll-spy tests deterministically. |
| src/components/OnPageIndex.tsx | New sticky sidebar index component (DOM scan + IntersectionObserver scroll-spy + “Back to top”). |
| src/components/OnPageIndex.test.tsx | Unit tests for heading discovery, active state behavior, bottom-of-page behavior, and click scrolling. |
| src/pages/resources/ResourcesUseCasesPage.tsx | Wraps content in an indexed container and adds ids to top-level h2s; mounts OnPageIndex. |
| src/pages/resources/ResourcesUseCasesPage.test.tsx | Verifies index entries match intended top-level sections and exclude non-indexed headings. |
| src/pages/resources/ResourcesMethodologyPage.tsx | Adds OnPageIndex and ids for major sections while keeping collapsible subsections excluded (no h2[id]). |
| src/pages/resources/ResourcesMethodologyPage.test.tsx | Verifies index entries reflect the intended top-level section order. |
| src/pages/resources/ResourcesHowToChooseAPathwayPage.tsx | Adds OnPageIndex and ids to the three top-level sections; keeps accordion rows out of the index. |
| src/pages/resources/ResourcesHowToChooseAPathwayPage.test.tsx | Verifies index entries match intended top-level sections and exclude the aside heading. |
| src/pages/resources/ResourcesFaqPage.tsx | Adds OnPageIndex, introduces stable section IDs, and anchors each top-level FAQ category h2. |
| src/pages/resources/ResourcesFaqPage.test.tsx | Verifies only the three category headings appear (not individual collapsed questions). |
| src/pages/resources/ResourcesUpdatesPage.tsx | Documents the intentional exclusion of the index on Updates per #802 scope. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+26
to
+49
| // Scan for indexable headings once, after the page's content has mounted. | ||
| // None of the pages using this component conditionally render their | ||
| // top-level sections, so a single scan is enough. This must be a passive | ||
| // effect (not useLayoutEffect): OnPageIndex is rendered as an earlier | ||
| // sibling of the container it reads, and React only attaches a later | ||
| // sibling's ref once the earlier sibling's own layout effects have run — | ||
| // so containerRef.current would still be null at that point. Passive | ||
| // effects run only after the whole tree has committed, so the ref is | ||
| // guaranteed to be attached by the time this runs, regardless of DOM order. | ||
| useEffect(() => { | ||
| const container = containerRef.current; | ||
| if (!container) return; | ||
|
|
||
| const elements = Array.from( | ||
| container.querySelectorAll<HTMLHeadingElement>("h2[id]"), | ||
| ); | ||
| const found = elements.map((el) => ({ | ||
| id: el.id, | ||
| label: el.textContent?.trim() ?? "", | ||
| })); | ||
|
|
||
| setHeadings(found); | ||
| setActiveId(found[0]?.id ?? null); | ||
| }, [containerRef]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The target was to improve the UX of navigating the Resource pages and prepare for linking from other pages to particular sections on the resource pages.
Related issues
Closes: #802
Testing
Added tests:
Manually validated the expected behavior as described in the A/Cs of the linked GH issue.
Checklist