Organize a multi-page Quarto website, configure reader-focused navigation and cross-references, diagnose render failures, and inspect the clean HTML artifact.
You will learn: Turn QMD source and project configuration into a complete, navigable documentation site and repair failures using file, line, link, and output evidence.
Practice in: A local Midnight Museum Quarto project; Colab is a reading companion rather than the site builder
A documentation site is not a pile of HTML files written by hand. Source pages, project configuration, navigation, assets, and a renderer combine into an output artifact. The source belongs in version control; the generated _site directory can be rebuilt and published after its checks pass.
This lesson asks:
Which files are source, configuration, cache, and public output?
How should navigation reflect reader tasks rather than alphabetical filenames?
Why should internal links point to QMD source paths?
When is preview useful, and why must deployment use a complete render?
How do you locate a failure in YAML, a page, a cross-reference, or generated output?
Do not hand-edit _site/api.html to fix source content. The next render will replace the edit. Find the owning QMD file or project configuration, repair it, and render again.
Quarto transforms reviewed source and configuration into a replaceable site artifact.
flowchart LR
A[QMD and Markdown source] --> D[Quarto render]
B[_quarto.yml] --> D
C[Images and styles] --> D
D --> E[_site HTML artifact]
E --> F[Inspection]
F --> G[Publication]
A minimal QMD page uses YAML front matter and meaningful headings:
---title: Rank Your First Museum Exhibitdescription: Follow a guided path from a clean project to one verified score.---## Before the museum opensUse Python 3.10 or newer and complete the project installation.## Rank the Moon Dial```pythonfrom museum_quest import rank_exhibitresult = rank_exhibit("Moon Dial", votes=4, minutes_open=75)print(result)```Expected result: `ExhibitScore(name='Moon Dial', score=44)`.
The title becomes the page heading and default navigation label. The description can support previews and metadata. The page itself retains the reader-focused prerequisites, action, and expected result from Lesson 2.
Quarto features should clarify the task. A normal note uses a callout:
::: {.callout-note title="Why 75 minutes adds four points"}Only complete 30-minute periods count. Seventy-five minutes contains twocomplete periods.:::
Do not put every paragraph into a colored box. Reserve callouts for information whose role—note, tip, warning, important point—helps a reader decide how to use it.
Link to source pages, not generated filenames
From tutorial.qmd, link to a sibling source:
[Look up the `rank_exhibit` contract](api.qmd "API reference")
Quarto resolves that source link to the appropriate output. A direct api.html link binds the source to one output format and is easier to break if the project later becomes a book or another format.
From root README.md, the same target uses its actual relative depth:
[Look up the `rank_exhibit` contract](docs/api.qmd "API reference")
Paths are relative to the page containing them, not to whichever terminal the author happens to use.
3. Design navigation around reader movement
The flat list works for five pages. Labels make the purpose even clearer:
website:title: Midnight Museum Questpage-navigation:truesearch:truesidebar:style: floatingcontents:-href: index.qmdtext: Start Here-href: tutorial.qmdtext: Guided Museum Visit-href: how-to-rank-exhibits.qmdtext: Change a Ranking-href: why-ranking-is-deterministic.qmdtext: Why Rankings Repeat-href: api.qmdtext: Public API
The order moves from entry to guided use, focused task, understanding, and exact lookup. Alphabetical order would begin with API, not the most useful entrance.
For a larger site, sections can group related pages:
website:sidebar:contents:-href: index.qmdtext: Start Here-section: Learncontents:- tutorial.qmd-section: Use the Packagecontents:- how-to-rank-exhibits.qmd- why-ranking-is-deterministic.qmd- api.qmd
Avoid creating a one-page section under every documentation type. A hierarchy should reduce choice, not make every click reveal another nearly empty menu.
Search helps when the site has enough content and readers know the term to find. It does not replace a clear entry journey for someone who does not yet know the function name.
Repository actions create feedback paths
A published project can expose edit and issue actions:
Use the real repository URL. A feedback link without ownership or response expectations is not a complete support plan, but it gives readers an observable route to report stale content.
A figure with an identifier can be referenced by name:
{#fig-reader-paths}The four destinations in @fig-reader-paths answer different reader questions.
Quarto requires a type prefix such as fig-, tbl-, or lst-. Use hyphens in identifiers and keep them stable when other pages link to them.
A table can carry a caption and ID:
| Reader | Destination ||---|---|| New learner | Tutorial || Active caller | API reference |: Reader questions choose documentation paths {#tbl-reader-paths}
Reference it as @tbl-reader-paths. The rendered number and link update if the table moves.
Do not cross-reference every short code block. A nearby sentence may be easier than “see Listing 14.” Use a reference when a reader needs to find or revisit a named object.
Diagnose an unresolved reference
Suppose the render warns that @fig-reader_path cannot be resolved. Compare the reference with the label:
There are two differences: underscore versus hyphen, and singular versus plural. Repair the source reference to the exact stable ID, then perform a full render and follow the link in HTML.
5. Preview quickly, render completely
From the docs/ project directory:
quarto preview
Preview starts a local server and rerenders affected pages while you work. It is useful for checking headings, navigation, and layout in a browser. Stop the server before treating its current screen as a deployable artifact.
From the repository root, target the project explicitly:
quarto render docs
A successful full render reports an output such as:
Output created: _site/index.html
When the project root is docs/, _site is normally docs/_site. Read paths in context instead of copying one output line into every project.
Why render again after preview?
a page may never have been opened during preview;
changes to _quarto.yml, shared includes, styles, or navigation affect more than the active page;
caches can preserve state that a clean build will not have; and
publication needs one complete artifact tied to reviewed source.
Clean generated output safely, rerender, and compare the named page inventory. Generated _site can be removed; QMD source cannot.
ERROR: YAMLException: bad indentation of a mapping entry at docs/_quarto.yml:9:7
Open the named file and line. Compare indentation with parent keys. Do not edit a QMD paragraph or generated HTML for a configuration parse error.
A common defect is:
website:sidebar:contents:- index.qmd
contents must be nested beneath sidebar:
website:sidebar:contents:- index.qmd
Missing source target
Unable to resolve link target: reference/api.qmd
Start from the source page containing the link. Resolve reference/api.qmd relative to that page. Check whether the link depth is wrong, the file moved, or navigation still names a retired route.
Page parses but a diagram fails
A Mermaid error belongs to the diagram source. Keep labels simple, quote punctuation-sensitive labels, and preserve the required execution options. Run the focused Mermaid parser and render again rather than replacing the diagram with an unverified screenshot.
Render succeeds but a page is missing
Inspect project render targets and sidebar paths. A page excluded by project configuration will not reappear because its old HTML remains in an uncleared _site. This is why a clean output directory matters: stale files can conceal a missing render target.
7. Compare toolchains without maintaining three sites
Quarto is the complete path here because this course already uses QMD, code examples, diagrams, and a Quarto website. Other projects may choose differently:
Sphinx has a mature Python domain and autodoc ecosystem for API-heavy libraries, often using reStructuredText or MyST.
MkDocs emphasizes Markdown-oriented documentation websites and a plugin ecosystem.
Quarto supports technical documents, executable content, cross-references, websites, books, and multiple output formats.
Choose from reader and maintainer needs: API generation, markup familiarity, execution model, extension ecosystem, output formats, accessibility, and team capacity. Do not build three versions before the project has one trustworthy site.
8. Lab: assemble the Midnight Museum site
Create the five-page source tree and _quarto.yml from this lesson. Your site must provide:
index.qmd with value, prerequisites, and direct tutorial link;
tutorial.qmd with the verified Moon Dial result;
how-to-rank-exhibits.qmd for changing one input;
why-ranking-is-deterministic.qmd explaining explicit inputs and no hidden state;
api.qmd describing the public signature, result, and failures;
reader-focused sidebar text and page navigation;
one figure or table with a stable cross-reference;
descriptive internal QMD links;
repository feedback actions only if a real URL is supplied.
Run:
quarto render docs
Verify:
from pathlib import Pathsite = Path("docs/_site")expected = {"index.html","tutorial.html","how-to-rank-exhibits.html","why-ranking-is-deterministic.html","api.html",}assert expected <= {path.name for path in site.glob("*.html")}
Then introduce and repair:
one incorrectly indented contents key;
one link to reference/api.qmd that should target api.qmd;
one cross-reference whose ID differs by an underscore;
one page removed from navigation while stale HTML remains.
Clear generated output before verifying the final repair so a stale file cannot produce a false pass.
Hint: build one navigable page before adding features
Start with index.qmd, tutorial.qmd, and a two-item sidebar. Render. Add one page and link at a time, rerendering after each structural change.
Reveal a complete minimal configuration
project:type: websiteoutput-dir: _sitewebsite:title: Midnight Museum Questpage-navigation:truesearch:truesidebar:style: floatingcontents:-href: index.qmdtext: Start Here-href: tutorial.qmdtext: Guided Museum Visit-href: how-to-rank-exhibits.qmdtext: Change a Ranking-href: why-ranking-is-deterministic.qmdtext: Why Rankings Repeat-href: api.qmdtext: Public APIformat:html:toc:true
The content of each page still owns reader quality. This configuration only makes the intended source set and order explicit.
Key points
Keep QMD, configuration, and assets as source; treat _site as replaceable output.
Design navigation around reader movement rather than filename order.
Link to source QMD paths so Quarto can resolve the chosen output format.
Use callouts and cross-references only when their structure helps the reader.
Preview accelerates local iteration; a clean complete render owns the deployment artifact.
Diagnose YAML, source-link, diagram, and stale-output failures at their owning layer.
Teach and maintain one suitable toolchain completely before comparing alternatives.