Skip to content

Further changes to tables of contents - #13766

Merged
simonbyford merged 2 commits into
mainfrom
more-toc-changes
May 16, 2025
Merged

simonbyford merged 2 commits into
mainfrom
more-toc-changes

Conversation

@simonbyford

@simonbyford simonbyford commented Apr 9, 2025

Copy link
Copy Markdown
Contributor

What does this change?

Makes two changes to the behaviour of the ToC (Table of Contents) component:

  1. always make the ToC sticky regardless of number of items
  2. automatically collapse the ToC when it becomes sticky (i.e. when it reaches the top of the viewport)

For 2) I went with the approach detailed here:

https://css-tricks.com/how-to-detect-when-a-sticky-element-gets-pinned/

There might be a less hacky way though?

Why?

Following on from #12895 and #13743 we got some feedback from Rich:

Can we make the logic so it's always sticky?

I don't know how inherently it's linked to the logic of the open vs. collapsed on page load. Currently when there is less than 5 the ToC is open on load, more than 5 collapsed. But obviously for a menu that is sticky but has less than 5 items, we want it to be open on load but collapse when it becomes sticky.

Hope that makes sense and I'm not over complicating things too much!

Screenshots

Before

sticky-before.mp4

After

sticky-after.mp4

@github-actions

github-actions Bot commented Apr 9, 2025

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Apr 9, 2025

Copy link
Copy Markdown

Size Change: +130 B (+0.01%)

Total Size: 974 kB

Filename Size Change
dotcom-rendering/dist/TableOfContents-importable.client.web.********************.js 3.66 kB +129 B (+3.65%)
ℹ️ View Unchanged
Filename Size Change
dotcom-rendering/dist/1008.client.web.********************.js 2.88 kB 0 B
dotcom-rendering/dist/1032.client.web.********************.js 3.31 kB 0 B
dotcom-rendering/dist/117.client.web.********************.js 2.87 kB 0 B
dotcom-rendering/dist/1562.client.web.********************.js 20.3 kB 0 B
dotcom-rendering/dist/1656.client.web.********************.js 49.6 kB 0 B
dotcom-rendering/dist/1823.client.web.********************.js 3.9 kB 0 B
dotcom-rendering/dist/2045.client.web.********************.js 2.63 kB 0 B
dotcom-rendering/dist/2161.client.web.********************.js 3.9 kB 0 B
dotcom-rendering/dist/223.client.web.********************.js 527 B 0 B
dotcom-rendering/dist/2270.client.web.********************.js 3.65 kB 0 B
dotcom-rendering/dist/2309.client.web.********************.js 3.27 kB 0 B
dotcom-rendering/dist/2345.client.web.********************.js 3.38 kB 0 B
dotcom-rendering/dist/2360.client.web.********************.js 20 kB 0 B
dotcom-rendering/dist/2502.client.web.********************.js 157 B 0 B
dotcom-rendering/dist/302.client.web.********************.js 11.2 kB 0 B
dotcom-rendering/dist/3292.client.web.********************.js 2.11 kB 0 B
dotcom-rendering/dist/3308.client.web.********************.js 3.12 kB 0 B
dotcom-rendering/dist/3384.client.web.********************.js 3.86 kB 0 B
dotcom-rendering/dist/3485.client.web.********************.js 4.67 kB 0 B
dotcom-rendering/dist/356.client.web.********************.js 6.4 kB 0 B
dotcom-rendering/dist/3598.client.web.********************.js 3.65 kB 0 B
dotcom-rendering/dist/3605.client.web.********************.js 15.1 kB 0 B
dotcom-rendering/dist/3619.client.web.********************.js 4.46 kB 0 B
dotcom-rendering/dist/3929.client.web.********************.js 3.45 kB 0 B
dotcom-rendering/dist/4133.client.web.********************.js 3.1 kB 0 B
dotcom-rendering/dist/4258.client.web.********************.js 4.08 kB 0 B
dotcom-rendering/dist/4306.client.web.********************.js 22.7 kB 0 B
dotcom-rendering/dist/4308.client.web.********************.js 3.57 kB 0 B
dotcom-rendering/dist/4324.client.web.********************.js 619 B 0 B
dotcom-rendering/dist/4457.client.web.********************.js 6.26 kB 0 B
dotcom-rendering/dist/4501.client.web.********************.js 4.29 kB 0 B
dotcom-rendering/dist/476.client.web.********************.js 5.42 kB 0 B
dotcom-rendering/dist/4776.client.web.********************.js 11.6 kB 0 B
dotcom-rendering/dist/5144.client.web.********************.js 2.55 kB 0 B
dotcom-rendering/dist/5448.client.web.********************.js 4.37 kB 0 B
dotcom-rendering/dist/545.client.web.********************.js 531 B 0 B
dotcom-rendering/dist/562.client.web.********************.js 11.5 kB 0 B
dotcom-rendering/dist/6038.client.web.********************.js 2.76 kB 0 B
dotcom-rendering/dist/6217.client.web.********************.js 3.75 kB 0 B
dotcom-rendering/dist/6480.client.web.********************.js 3.68 kB 0 B
dotcom-rendering/dist/6540.client.web.********************.js 2.62 kB 0 B
dotcom-rendering/dist/6541.client.web.********************.js 2.91 kB 0 B
dotcom-rendering/dist/6555.client.web.********************.js 5.45 kB 0 B
dotcom-rendering/dist/6562.client.web.********************.js 439 B 0 B
dotcom-rendering/dist/6584.client.web.********************.js 2.68 kB 0 B
dotcom-rendering/dist/6722.client.web.********************.js 3.03 kB 0 B
dotcom-rendering/dist/6873.client.web.********************.js 4.13 kB 0 B
dotcom-rendering/dist/695.client.web.********************.js 4.51 kB 0 B
dotcom-rendering/dist/7116.client.web.********************.js 23.2 kB 0 B
dotcom-rendering/dist/732.client.web.********************.js 3.09 kB 0 B
dotcom-rendering/dist/7398.client.web.********************.js 3.57 kB 0 B
dotcom-rendering/dist/7708.client.web.********************.js 5.05 kB 0 B
dotcom-rendering/dist/7725.client.web.********************.js 5.59 kB 0 B
dotcom-rendering/dist/7927.client.web.********************.js 2.76 kB 0 B
dotcom-rendering/dist/8151.client.web.********************.js 4.17 kB 0 B
dotcom-rendering/dist/8212.client.web.********************.js 5.04 kB 0 B
dotcom-rendering/dist/8385.client.web.********************.js 3.88 kB 0 B
dotcom-rendering/dist/8387.client.web.********************.js 2.78 kB 0 B
dotcom-rendering/dist/8436.client.web.********************.js 3.63 kB 0 B
dotcom-rendering/dist/8602.client.web.********************.js 3.39 kB 0 B
dotcom-rendering/dist/8619.client.web.********************.js 4.44 kB 0 B
dotcom-rendering/dist/864.client.web.********************.js 3.17 kB 0 B
dotcom-rendering/dist/8942.client.web.********************.js 4.44 kB 0 B
dotcom-rendering/dist/8973.client.web.********************.js 16.5 kB 0 B
dotcom-rendering/dist/9135.client.web.********************.js 3.54 kB 0 B
dotcom-rendering/dist/9139.client.web.********************.js 3.13 kB 0 B
dotcom-rendering/dist/9376.client.web.********************.js 2.52 kB 0 B
dotcom-rendering/dist/960.client.web.********************.js 7.99 kB 0 B
dotcom-rendering/dist/967.client.web.********************.js 2.87 kB 0 B
dotcom-rendering/dist/9822.client.web.********************.js 7.67 kB 0 B
dotcom-rendering/dist/9837.client.web.********************.js 3.29 kB 0 B
dotcom-rendering/dist/9870.client.web.********************.js 4.77 kB 0 B
dotcom-rendering/dist/Accessibility-importable.client.web.********************.js 8.43 kB 0 B
dotcom-rendering/dist/AdBlockAsk-importable.client.web.********************.js 2.99 kB 0 B
dotcom-rendering/dist/AdPortals-importable.client.web.********************.js 4.76 kB 0 B
dotcom-rendering/dist/AlreadyVisited-importable.client.web.********************.js 425 B 0 B
dotcom-rendering/dist/AppsEpic-importable.client.web.********************.js 3.61 kB 0 B
dotcom-rendering/dist/AppsFooter-importable.client.web.********************.js 2.69 kB 0 B
dotcom-rendering/dist/AppsLightboxImage-importable.client.web.********************.js 2.66 kB 0 B
dotcom-rendering/dist/AppsLightboxImageStore-importable.client.web.********************.js 2.6 kB 0 B
dotcom-rendering/dist/AudioAtomWrapper-importable.client.web.********************.js 2.76 kB 0 B
dotcom-rendering/dist/AudioPlayerWrapper-importable.client.web.********************.js 6.61 kB 0 B
dotcom-rendering/dist/AustralianTerritorySwitcher-importable.client.web.********************.js 4.61 kB 0 B
dotcom-rendering/dist/Branding-importable.client.web.********************.js 2.89 kB 0 B
dotcom-rendering/dist/braze-web-sdk-core.client.web.********************.js 67.7 kB 0 B
dotcom-rendering/dist/BrazeMessaging-importable.client.web.********************.js 1.68 kB 0 B
dotcom-rendering/dist/CalloutBlockComponent-importable.client.web.********************.js 6.73 kB 0 B
dotcom-rendering/dist/CalloutEmbedBlockComponent-importable.client.web.********************.js 5.77 kB 0 B
dotcom-rendering/dist/CardCommentCount-importable.client.web.********************.js 2.67 kB 0 B
dotcom-rendering/dist/Carousel-importable.client.web.********************.js 6.67 kB 0 B
dotcom-rendering/dist/CarouselForNewsletters-importable.client.web.********************.js 4.57 kB 0 B
dotcom-rendering/dist/ChartAtom-importable.client.web.********************.js 539 B 0 B
dotcom-rendering/dist/CommentCount-importable.client.web.********************.js 2.3 kB 0 B
dotcom-rendering/dist/CrosswordComponent-importable.client.web.********************.js 2.88 kB 0 B
dotcom-rendering/dist/DiscussionApps-importable.client.web.********************.js 1.07 kB 0 B
dotcom-rendering/dist/DiscussionMeta-importable.client.web.********************.js 2.41 kB 0 B
dotcom-rendering/dist/DiscussionWeb-importable.client.web.********************.js 3.45 kB 0 B
dotcom-rendering/dist/DocumentBlockComponent-importable.client.web.********************.js 2.85 kB 0 B
dotcom-rendering/dist/Dropdown-importable.client.web.********************.js 1.72 kB 0 B
dotcom-rendering/dist/EditionSwitcherBanner-importable.client.web.********************.js 4.45 kB 0 B
dotcom-rendering/dist/EmbedBlockComponent-importable.client.web.********************.js 3.98 kB 0 B
dotcom-rendering/dist/EnhancePinnedPost-importable.client.web.********************.js 2.02 kB 0 B
dotcom-rendering/dist/FetchOnwardsData-importable.client.web.********************.js 1.94 kB 0 B
dotcom-rendering/dist/FilterKeyEventsToggle-importable.client.web.********************.js 3.72 kB 0 B
dotcom-rendering/dist/FocusStyles-importable.client.web.********************.js 618 B 0 B
dotcom-rendering/dist/FollowWrapper-importable.client.web.********************.js 2.53 kB 0 B
dotcom-rendering/dist/FootballMatchesPageWrapper-importable.client.web.********************.js 7.2 kB 0 B
dotcom-rendering/dist/FootballTablesCompetitionSelect-importable.client.web.********************.js 3.26 kB 0 B
dotcom-rendering/dist/FooterLabel-importable.client.web.********************.js 364 B 0 B
dotcom-rendering/dist/FooterReaderRevenueLinks-importable.client.web.********************.js 3.43 kB 0 B
dotcom-rendering/dist/frameworks.client.web.********************.js 20.9 kB 0 B
dotcom-rendering/dist/FrontSubNav-importable.client.web.********************.js 7.5 kB 0 B
dotcom-rendering/dist/GetCricketScoreboard-importable.client.web.********************.js 6.29 kB 0 B
dotcom-rendering/dist/GetMatchNav-importable.client.web.********************.js 11.5 kB 0 B
dotcom-rendering/dist/GetMatchStats-importable.client.web.********************.js 8.12 kB 0 B
dotcom-rendering/dist/GetMatchTabs-importable.client.web.********************.js 2.58 kB 0 B
dotcom-rendering/dist/guardian-braze-components-banner.client.web.********************.js 16.1 kB 0 B
dotcom-rendering/dist/guardian-braze-components-end-of-article.client.web.********************.js 10.2 kB 0 B
dotcom-rendering/dist/GuideAtomWrapper-importable.client.web.********************.js 782 B 0 B
dotcom-rendering/dist/index.client.web.********************.js 46.4 kB +1 B (0%)
dotcom-rendering/dist/InstagramBlockComponent-importable.client.web.********************.js 2.9 kB 0 B
dotcom-rendering/dist/InteractiveAtomMessenger-importable.client.web.********************.js 854 B 0 B
dotcom-rendering/dist/InteractiveBlockComponent-importable.client.web.********************.js 8.83 kB 0 B
dotcom-rendering/dist/InteractiveContentsBlockComponent-importable.client.web.********************.js 3.78 kB 0 B
dotcom-rendering/dist/KeyEventsCarousel-importable.client.web.********************.js 5.69 kB 0 B
dotcom-rendering/dist/KnowledgeQuizAtom-importable.client.web.********************.js 3.19 kB 0 B
dotcom-rendering/dist/LatestLinks-importable.client.web.********************.js 7.98 kB 0 B
dotcom-rendering/dist/LightboxHash-importable.client.web.********************.js 436 B 0 B
dotcom-rendering/dist/LightboxLayout-importable.client.web.********************.js 6.58 kB 0 B
dotcom-rendering/dist/LiveBlogEpic-importable.client.web.********************.js 3.55 kB 0 B
dotcom-rendering/dist/LiveblogGutterAskWrapper-importable.client.web.********************.js 2.49 kB 0 B
dotcom-rendering/dist/LiveblogNotifications-importable.client.web.********************.js 4.84 kB 0 B
dotcom-rendering/dist/Liveness-importable.client.web.********************.js 4.71 kB 0 B
dotcom-rendering/dist/LoopVideo-importable.client.web.********************.js 3.67 kB 0 B
dotcom-rendering/dist/ManyNewsletterSignUp-importable.client.web.********************.js 7.65 kB 0 B
dotcom-rendering/dist/MapEmbedBlockComponent-importable.client.web.********************.js 6.04 kB 0 B
dotcom-rendering/dist/Metrics-importable.client.web.********************.js 2.7 kB 0 B
dotcom-rendering/dist/MostViewedFooter-importable.client.web.********************.js 3.85 kB 0 B
dotcom-rendering/dist/MostViewedFooterData-importable.client.web.********************.js 5.97 kB 0 B
dotcom-rendering/dist/MostViewedRightWithAd-importable.client.web.********************.js 5.24 kB 0 B
dotcom-rendering/dist/OnwardsUpper-importable.client.web.********************.js 5.32 kB 0 B
dotcom-rendering/dist/PersonalityQuizAtom-importable.client.web.********************.js 3.35 kB 0 B
dotcom-rendering/dist/ProfileAtom-importable.client.web.********************.js 545 B 0 B
dotcom-rendering/dist/ProfileAtomWrapper-importable.client.web.********************.js 805 B 0 B
dotcom-rendering/dist/PulsingDot-importable.client.web.********************.js 749 B 0 B
dotcom-rendering/dist/QandaAtom-importable.client.web.********************.js 542 B 0 B
dotcom-rendering/dist/ReaderRevenueDev-importable.client.web.********************.js 470 B 0 B
dotcom-rendering/dist/readerRevenueDevUtils.client.web.********************.js 1.7 kB 0 B
dotcom-rendering/dist/RelativeTime-importable.client.web.********************.js 2.56 kB 0 B
dotcom-rendering/dist/RichLinkComponent-importable.client.web.********************.js 6.14 kB 0 B
dotcom-rendering/dist/ScrollableFeature-importable.client.web.********************.js 6.63 kB 0 B
dotcom-rendering/dist/ScrollableHighlights-importable.client.web.********************.js 7.29 kB 0 B
dotcom-rendering/dist/ScrollableMedium-importable.client.web.********************.js 2.11 kB 0 B
dotcom-rendering/dist/ScrollableSmall-importable.client.web.********************.js 2.17 kB 0 B
dotcom-rendering/dist/SecureSignup-importable.client.web.********************.js 4.2 kB 0 B
dotcom-rendering/dist/SendTargetingParams-importable.client.web.********************.js 2.21 kB 0 B
dotcom-rendering/dist/sentry.client.web.********************.js 802 B 0 B
dotcom-rendering/dist/SetABTests-importable.client.web.********************.js 3.91 kB 0 B
dotcom-rendering/dist/SetAdTargeting-importable.client.web.********************.js 487 B 0 B
dotcom-rendering/dist/ShareButton-importable.client.web.********************.js 2.18 kB 0 B
dotcom-rendering/dist/shimport.client.web.********************.js 2.8 kB 0 B
dotcom-rendering/dist/ShowHideContainers-importable.client.web.********************.js 893 B 0 B
dotcom-rendering/dist/ShowMore-importable.client.web.********************.js 919 B 0 B
dotcom-rendering/dist/SignInGateMain.client.web.********************.js 1.11 kB 0 B
dotcom-rendering/dist/SignInGateMainCheckoutComplete.client.web.********************.js 2.6 kB 0 B
dotcom-rendering/dist/SignInGateSelector-importable.client.web.********************.js 4.97 kB 0 B
dotcom-rendering/dist/SlideshowCarousel-importable.client.web.********************.js 4.56 kB 0 B
dotcom-rendering/dist/SlotBodyEnd-importable.client.web.********************.js 4.9 kB 0 B
dotcom-rendering/dist/SpotifyBlockComponent-importable.client.web.********************.js 5.8 kB 0 B
dotcom-rendering/dist/StickyBottomBanner-importable.client.web.********************.js 6.13 kB 0 B
dotcom-rendering/dist/SubNav-importable.client.web.********************.js 2.44 kB 0 B
dotcom-rendering/dist/TimelineAtom-importable.client.web.********************.js 1.23 kB 0 B
dotcom-rendering/dist/Titlepiece-importable.client.web.********************.js 13.6 kB 0 B
dotcom-rendering/dist/TopBar-importable.client.web.********************.js 8.85 kB 0 B
dotcom-rendering/dist/TopBarSupport-importable.client.web.********************.js 2.49 kB 0 B
dotcom-rendering/dist/TweetBlockComponent-importable.client.web.********************.js 1.13 kB 0 B
dotcom-rendering/dist/UnsafeEmbedBlockComponent-importable.client.web.********************.js 2.92 kB 0 B
dotcom-rendering/dist/VideoFacebookBlockComponent-importable.client.web.********************.js 6.06 kB 0 B
dotcom-rendering/dist/VineBlockComponent-importable.client.web.********************.js 3.32 kB 0 B
dotcom-rendering/dist/YoutubeBlockComponent-importable.client.web.********************.js 843 B 0 B

compressed-size-action

@github-actions

github-actions Bot commented Apr 9, 2025

Copy link
Copy Markdown

@simonbyford
simonbyford marked this pull request as ready for review April 14, 2025 15:25
@github-actions

Copy link
Copy Markdown

Hello 👋! When you're ready to run Chromatic, please apply the run_chromatic label to this PR.

You will need to reapply the label each time you want to run Chromatic.

Click here to see the Chromatic project.

@simonbyford simonbyford added the run_chromatic Runs chromatic when label is applied label Apr 14, 2025
@github-actions github-actions Bot removed the run_chromatic Runs chromatic when label is applied label Apr 14, 2025
Comment thread dotcom-rendering/src/components/TableOfContents.importable.tsx
@simonbyford simonbyford added the run_chromatic Runs chromatic when label is applied label May 14, 2025
@github-actions github-actions Bot removed the run_chromatic Runs chromatic when label is applied label May 14, 2025

const observer = new IntersectionObserver(
([e]) => {
// Automatically collapse the ToC when it becomes sticky (i.e. when it reaches the top of the viewport)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also add a comment that explains how the 1px trick and why we use boundingClientRect a bit more? Perhaps a link to the article that explains how this 'trick' works?

https://css-tricks.com/how-to-detect-when-a-sticky-element-gets-pinned/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the comments

Comment on lines +142 to +144
const tocElement = document.querySelector(
'[data-component="table-of-contents"]',
) as HTMLElement;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to use a ref here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good shout, I've made that change

@arelra arelra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@simonbyford simonbyford added the run_chromatic Runs chromatic when label is applied label May 16, 2025
@github-actions github-actions Bot removed the run_chromatic Runs chromatic when label is applied label May 16, 2025
@simonbyford
simonbyford merged commit e37748f into main May 16, 2025
@simonbyford
simonbyford deleted the more-toc-changes branch May 16, 2025 08:30
@prout-bot

Copy link
Copy Markdown

Seen on PROD (merged by @simonbyford 10 minutes and 3 seconds ago) Please check your changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants