Skip to content

Implement scrolling table of contents#56

Merged
DanilaFe merged 8 commits intochapel-lang:mainfrom
DanilaFe:scrolling-toc
Feb 24, 2026
Merged

Implement scrolling table of contents#56
DanilaFe merged 8 commits intochapel-lang:mainfrom
DanilaFe:scrolling-toc

Conversation

@DanilaFe
Copy link
Contributor

@DanilaFe DanilaFe commented Feb 20, 2026

This PR implements a scrolling table of contents, closes #40.

The steps:

  • As noted in the original issue, left sidenotes would overlap with the table of contents if it scrolled. To avoid this, configure Hugo to track whether left sidenotes were used in an article. Also configure Hugo to make the table of contents sticky only if no left sidenotes were found.
  • Configure the .sticky class to use the position: sticky CSS property.
    • Specifically, position: sticky causes the element that's sticky to attach to the top of the window if its top is about to go past the edge, and travel with it as far as its parent container will allow.
    • The parent container for the table of contents is the .table-of-contents class. Adjust its CSS properties to make it as big as the post content, to allow the table of contents to travel all along it, but no higher or lower.
    • All this does not apply if we are in a world with prefers-reduced-motion, which is a CSS accessibility property.
  • A danger with this approach is that the table of contents is bigger than the viewport. This is particularly likely for posts like Advent of Code day 11. In this case, the sticky table of contents would always have its top visible, but its bottom out of sight.
    • The solution is to disable stickiness if the TOC is too big. This can only be done in JS (no way to query the TOC's size in CSS).
    • Since browsers with JS disabled would not be able to guard against this situation with JS, use a <noscript> tag to reset position back to relative instead of sticky when JS is not present.
    • Otherwise, add a resize handler to add or remove an additional class, overfull that similarly undoes stickiness.
  • To help the user keep track of where they are in the table of contents, add more JS to dynamically calculate the most recent headers.

While there, I noticed that we don't use numberedsidenote.html, so I deleted it.

Reviewed by @e-kayrakli -- thanks!

tocdemo

Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
Signed-off-by: Danila Fedorin <daniel.fedorin@hpe.com>
@bradcray
Copy link
Member

I just did a short test-drive of this and liked the result. I have not done anything to review the PR itself (yet, at least)

@DanilaFe DanilaFe merged commit 35cb228 into chapel-lang:main Feb 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can we make the table of contents stay at the top of the visible window?

3 participants