Skip to content

Navigation ordering, and two fixes for the moment a page loads - #1159

Merged
mikebarkmin merged 7 commits into
mainfrom
claude/hyperbook-navigation-order-and-load
Aug 7, 2026
Merged

Navigation ordering, and two fixes for the moment a page loads#1159
mikebarkmin merged 7 commits into
mainfrom
claude/hyperbook-navigation-order-and-load

Conversation

@mikebarkmin

Copy link
Copy Markdown
Member

The rest of #1158, rebuilt on top of main now that #1153 has shipped. The links, the emojis and the bookmarks are already released, so this branch carries only what was left.

Navigation

Pages were rendered before the sections of the same level, so a page could not sit after or between them. The index of a page and the index of a section are one order now, at every level, so a subsection can sit between two pages of its section.

The reading order follows the same order, so the previous and next buttons, the breadcrumb and ::pagelist agree with the sidebar. That order lives in one place, sortNavigation in @hyperbook/types, instead of once in the shell and twice in a page list. One function renders a level of the navigation and calls itself through the section it renders, which also dropped the second copy of the merge that existed for sections shown as a page.

Without an index nothing moves: a page still comes before a section, and a page wins a tie. A book that indexes its sections but leaves it off a page does move that page behind them, which is why the documentation gives its changelog page an index and shifts the sections after it. Both website books render the same navigation as before.

The pages of a section are also indented now. They sat one pixel to the right of a page of the level above, so only a hairline told the two levels apart. That was harmless while every page came before every section.

Loading

Two reasons a page looked collapsed for a moment:

  • A custom element renders its children until it is upgraded, and a side drawer is only hidden by its shadow root. The search drawer painted over the header and the table of contents drawer over the article until side-drawer.js had run. Measured while undefined, that was 500x98 over the header and 500x216 over the article.
  • The script that writes the light and dark stylesheets was a file. Nothing can paint before those stylesheets are there, so every first paint waited for a round trip to fetch 1.5 kB and then another for the stylesheets themselves. It is part of the page now, which measured the first contentful paint of the documentation going from 1128 ms to 984 ms over a connection throttled to 1.5 Mbit/s with 100 ms of latency. A mode the reader picked before still wins over the system preference, in both directions.

Testing

272 tests pass. New tests cover the navigation order at the top level and inside a section: a section between two pages, a page after a section, a subsection between two pages of its section, a page winning a tie, and pages staying before sections when nothing has an index.

The rest was checked in Chromium against a real build: the drawer flash before and after, the first paint measurement, and the navigation with three levels of subsections.

Note on the changelog

The entries here were written while v0.101.0 was still open. That release has shipped, so they moved to a v0.102.0 section, assuming the minor in these changesets is the next thing to land.


Generated by Claude Code

claude added 6 commits August 7, 2026 11:56
A custom element renders its children until it is upgraded, and a side
drawer keeps its closed state in its shadow root. The script that defines
it is an async module, so it runs after the first paint: until then the
search drawer painted over the header and the table of contents drawer
over the article, which read as a collapsed layout for a moment.

Measured while undefined, the search drawer was 500x98 over the header
and the table of contents drawer 500x216 over the article. The nav
drawer was not visible on a wide screen, because it sits in the mobile
nav, which is hidden there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
The light and dark stylesheets sit in a noscript element and are written
into the page by a script. Nothing can paint before they are there, so
loading that script as a file put a round trip in front of every first
paint, and a second one in front of the stylesheets it writes.

The script is 1.5 kB, so it is part of the page now. On the
documentation, over a connection throttled to 1.5 Mbit/s with 100 ms of
latency, the first contentful paint went from a median of 1128 ms to
984 ms over seven runs each.

The behaviour is unchanged: a mode the reader picked before still wins
over the system preference, in both directions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
Pages were rendered before the sections of the same level, so a page
could not sit after or between them. The index of a page and the index
of a section are one order now, and the navigation renders a run of
pages as a list, broken by every section that falls between them.

The reading order follows the same order, so the previous and next
buttons, the breadcrumb and pagelist agree with the sidebar. That order
lives in one place now, instead of once in the shell and twice in the
page list.

Without an index nothing moves: a page still comes before a section, and
a page wins a tie against a section. A book that indexes its sections
but not a page does move that page behind them, which is why the
documentation now gives its changelog page an index and shifts the
sections after it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
A page of a section sat one pixel to the right of a page of the level
above, so the only thing telling the two levels apart was the hairline
on the left of the list. That was harmless while every page came before
every section, but a page can sit after a section now, and it read as
one more page of that section.

The pages of a section are indented by 0.75rem, which puts them 13px in
instead of 1px, and a section block keeps a little room below it. Both
are scoped to a real section, so a virtual section still renders its
pages at the level of its parent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
Only the top level of the navigation shared one order. Inside a section
the subsections were still rendered after every page of that section, so
a subsection could not sit between two pages, and the sidebar disagreed
with the previous and next buttons, which already followed the index.

One function renders a level now and calls itself through the section it
renders, which also drops the second copy of the merge that existed for
sections shown as a page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
The entries were written while the previous release was still open. That
release has shipped, so the drawers, the first paint and the navigation
order belong to the next one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperbook-4fwa Ready Ready Preview Aug 7, 2026 12:12pm

sortNavigation concatenated the pages and the sections and sorted the
result, which reordered a list a caller had already put in order. Reading
a hyperbook orders both lists, so the only thing left to do is weave them
together. It merges them now, which keeps each list as it was given and
still lets an index place a section between two pages.

This restores the order the page list produces for a virtual section,
where the pages are kept as they are instead of the section's own page
being pulled to the front.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
@mikebarkmin
mikebarkmin merged commit 9bdb389 into main Aug 7, 2026
3 checks passed
@mikebarkmin
mikebarkmin deleted the claude/hyperbook-navigation-order-and-load branch August 7, 2026 12:26
@github-actions github-actions Bot mentioned this pull request Aug 7, 2026
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.

2 participants