Skip to content

Sidebar TOC section collapses after clicking an index page's title #910

Description

@henryiii

After moving the scientific-python development guide to MystMD, we ran into a bug: clicking on a page causes the animation for expanding the subpages, but then the new page loads and everything is closed. This makes it hard to navigate to the guide pages unless you know about the little </v arrow. This only happens for sites that have pages with subpages; pure subpages without parent pages work fine because it's all really just the same thing as the </v button.

I've added the output from a Claude investigation below. The suggested fix from that is:

Include the computed value in the dependency array so the effect re-applies once the path settles:

useEffect(() => {
  if (nav.state === 'idle') setOpen(startOpen);
}, [nav.state, startOpen]);

(This is also more correct generally — any path change that flips startOpen should re-sync the collapsible.)

I can make a PR for that if you want.

🤖 AI issue text 🤖

Title: Sidebar TOC section collapses after clicking an index page's title (should stay expanded)

Body:

Describe the bug

In the book theme, when a TOC entry has children (an index page with subpages), clicking the name of that entry navigates to its index page but leaves the section collapsed. You can watch the expand animation start and then the section collapses again once the page loads.

Clicking the chevron/dropdown arrow works fine (it just toggles open state with no navigation). The problem is specific to clicking the entry's title link.

Expected: when you're on an index page, its subpages should be expanded by default (and stay expanded after navigating to it).

To reproduce

  1. Build a site with a TOC where a top-level entry has children, e.g.:
    toc:
      - file: index.md
      - file: guides/index.md
        children:
          - file: guides/a.md
          - file: guides/b.md
  2. From a different page (with the guides section collapsed), click the "guides" title in the sidebar.
  3. The section briefly animates open, then collapses once guides/index loads.

Seen on @myst-theme/site@1.3.1 (book theme).

Root cause

In [packages/site/src/components/Navigation/TableOfContentsItems.tsx](https://github.com/jupyter-book/myst-theme/blob/main/packages/site/src/components/Navigation/TableOfContentsItems.tsx), NestedToc:

const startOpen = childrenOpen([heading], pathname, baseurl).includes(heading.id);
const nav = useNavigation();
const [open, setOpen] = React.useState(startOpen);
useEffect(() => {
  if (nav.state === 'idle') setOpen(startOpen);
}, [nav.state]);           // <-- only depends on nav.state

The intent is correct — childrenOpen / pathnameMatchesHeading already match an entry against its own index path (including the …/index case), so startOpen is true when you're on the entry's index page.

The problem is the effect's dependency array: it re-runs only on the nav.state transition, not when pathname / startOpen change. Clicking the title link optimistically opens the section (onClick={() => setOpen(heading.path ? true : !open)} — the animation you see), but if pathname updates in a separate commit from the nav.state → 'idle' transition, the effect fires with the stale (pre-navigation) startOpen (false for the just-navigated section) and never re-runs to pick up the corrected true. So it latches collapsed.

Suggested fix

Include the computed value in the dependency array so the effect re-applies once the path settles:

useEffect(() => {
  if (nav.state === 'idle') setOpen(startOpen);
}, [nav.state, startOpen]);

(This is also more correct generally — any path change that flips startOpen should re-sync the collapsible.)

Related

#635 / #647 covered the static-HTML variant of "sidebar stays collapsed" and are fixed; this is the client-side navigation case, which I don't see tracked in an open issue.

Want me to also draft the one-line PR (fork, patch, conventional-commit message) so you can open it alongside the issue?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions