Sidebar
markdown source of this page
The page as a markdown file: index.md
+++
title = "Sidebar"
subtitle = "the page tree, the sections a reader shuts, and what the browser remembers"
status = "approved"
intent = """
The sidebar exists so that a reader can see where they are in the wiki and reach any other page from
wherever they are reading. A wiki with many pages should not cost a reader a walk past the parts they are
not using, and moving from one page to the next should not undo what they set up.
"""
[[infobox]]
group = "Rules"
rows = [
{ label = "Section header", value = "shuts and opens its pages", cite = "control" },
{ label = "Stored", value = "the sections a reader shut", cite = "stored" },
{ label = "Direct arrival", value = "opens the page's own section", cite = "arrival" },
{ label = "Page list", value = "scrolls on its own", note = "logo and search stay put", cite = "rail" },
]
+++
The sidebar holds the whole wiki, with the site's name and the search box above the page list.[^rail] **The
sidebar is exactly the window's height and never scrolls as a whole**: only the list beneath the search box
scrolls, and scrolling it never moves the article.[^rail] The rest of the layout is described on
[Layout](../layout.md).
## Page tree
Pages beneath another hang from it as a tree.[^nest] **The sidebar marks where the reader is**: pages above
the current one are bold, and its tree lines take the link color.[^branch] A page far down a long list opens
with its own link in view.[^current] Lines across the sidebar set off the logo, the search box and each
section, whose name is in capitals, and the scroll bar sits at the edge.[^section]
## Sections
**A section's name is a button across the full width of the sidebar**, with a mark at its right that turns
as the section shuts.[^control] Pressing it slides that section's pages up or down.[^slide] A shut section
is out of reach of the keyboard as well as out of sight, so tabbing through the sidebar walks past
it.[^slide] The button beside the search box shuts every section at once, and opens every section once all
of them are shut.[^all] No section may go without a name, and no two may share one, because the name is
what a section is remembered by.[^named]
## Storage
The sections a reader shut are stored in their browser under a key carrying the site's name, so two wikis
published at one address remember their own.[^stored] They are applied before the sidebar is drawn, so a reader never
sees a section opening or closing as a page arrives.[^stored] Where the page list was scrolled belongs to
the browser tab rather than the device, and the list opens where the reader left it.[^place]
**Following a link straight to a page opens the section that page sits in**, whatever was stored, and
stores nothing — so one shared link cannot undo what the reader chose.[^arrival] Reloading is not
arriving: a section just shut stays shut.[^arrival]
[^rail]: `src/builder/assets/wiki.css` — `.rail-in` is sticky and the window's height; `.rail #nav` takes
the space left under the logo and search, scrolls with `overflow-y: auto`, and keeps the scroll with
`overscroll-behavior: contain`.
[^nest]: `src/builder/assets/wiki.css` — `.rail li li::before` draws the line beside a nested page and
stops it at the leg on `:last-child`, `.rail li li::after` draws the leg, and `.rail li li a` sets
the link smaller.
[^branch]: `src/builder/build.py` — `render_nav()` gives the link of every page above the current one the
class `up`, and the list beneath the current page or a page above it the class `here`;
`src/builder/assets/wiki.css` makes `a.up` bold and draws the line and legs of `ul.here` in the link
color.
[^current]: `src/builder/assets/wiki.js` — `placeList()` scrolls `#nav` so its `a.on` link is in view,
without moving the article, and only when the restored place left it out of sight.
[^section]: `src/builder/assets/wiki.css` — `.logo::after` and `.sbox::after` draw the lines below the
logo and the search box, `.rail h5` draws each section's name in capitals under a line that reaches
both edges of the rail, `.rail #nav > h5:first-child` leaves the line off the first, and
`.rail #nav` reaches the rail's edges and carries its padding inside, so its scroll bar is on the edge.
[^control]: `src/builder/build.py` — `render_nav()` writes each section as an `h5` carrying its key,
holding a button and `CHEVRON`; `src/builder/assets/wiki.css` — `.rail h5 button` carries the header's
padding and its bleed to the rail's edges, so the whole row takes a press, and `h5.shut .chev` turns
the mark.
[^slide]: `src/builder/assets/wiki.css` — `.fold` goes from `grid-template-rows: 1fr` to `0fr`, and
`h5.shut + .fold > ul` sets `visibility: hidden` after the slide, which takes its links out of the
page; `src/builder/assets/wiki.js` — a click on a section's button toggles `shut` and sets
`aria-expanded`.
[^all]: `src/builder/assets/template.html` — the `foldall` button stands beside the search box;
`src/builder/assets/wiki.js` — its click shuts every section, or opens every one when all are shut,
and `showFoldAll()` names which it will do next.
[^named]: `src/builder/config.py` — `read_config()` refuses a section with no title, and two sections that
share one.
[^stored]: `src/builder/build.py` — `render_page()` fills `nav_key` with `wiki-nav-shut:` and the site's
name slugged; `src/builder/assets/template.html` — the script in the head reads that key and writes a
rule shutting each stored section before the sidebar is parsed; `src/builder/assets/wiki.js` —
`rememberShut()` writes back the sections marked `shut`.
[^place]: `src/builder/assets/wiki.js` — `keepPlace()` writes `#nav.scrollTop` to the tab's own storage on
`pagehide` and on `visibilitychange`, and `placeList()` reads it back; the `pageshow` listener restores
nothing when the page came from the back/forward cache.
[^arrival]: `src/builder/build.py` — `current_section()` gives the key of the section holding the page
being drawn; `src/builder/assets/template.html` — the head leaves that section out of the rule it
writes when the tab has seen no page yet and the browser reports no reload, and records what it
decided on the document for `src/builder/assets/wiki.js` to apply.
Last updated 17 September 2026