Path: blob/main/llm-docs/revealjs-format-architecture.md
6832 views
------Revealjs Format Architecture
How Quarto configures reveal.js presentations, covering metadata handling, template rendering, and the division of responsibilities between TypeScript and Pandoc templates.
Key Files
| File | Role |
|---|---|
src/format/reveal/format-reveal.ts | Format definition, metadata normalization, extras |
src/format/reveal/constants.ts | Metadata key constants |
src/resources/formats/revealjs/pandoc/template.html | Quarto's active Pandoc template |
src/resources/formats/revealjs/pandoc/revealjs.template | Reference copy of Pandoc's upstream template |
Two Template Files
Quarto maintains two revealjs template files. They serve different purposes:
revealjs.template is a direct copy of Pandoc's default.revealjs, auto-generated by package/src/common/update-pandoc.ts during Pandoc version updates. Do not modify this file — changes will be overwritten on the next Pandoc update.
template.html is Quarto's active template, specified in formatExtras() via templateContext. It diverges from the upstream template where Quarto needs different behavior (type-safe rendering, additional features, etc.).
Metadata Handling Pattern
Revealjs configuration flows through three stages with distinct responsibilities:
Stage 1: Normalization — revealResolveFormat()
Maps user-facing YAML keys to reveal.js configuration keys. Runs early in format resolution.
Responsibilities:
Map compound YAML structures to flat metadata (e.g.,
scroll-view.snap→scrollSnap)Normalize values (e.g.,
navigationMode: "vertical"→"default")Create helper flags for template type handling (e.g.,
scrollProgressAuto)Remove intermediate metadata keys (e.g., delete
scroll-viewafter extracting sub-options)
Does NOT set defaults — only transforms what the user provided.
Stage 2: Defaults — extras.metadata in formatExtras()
Sets opinionated default values that can be overridden by user metadata. These are the lowest priority in the metadata chain.
Setting defaults explicitly (rather than relying on Pandoc's defField) ensures the template always has values to render.
Stage 3: Post-processing — fixupRevealJsInitialization()
DOM manipulation of the rendered HTML, handling values that can't be fixed in the template:
Quoting
slideNumberstring values (e.g.,h.v→'h.v')Quoting percentage-based
width/heightvaluesInjecting
extraConfigvalues (options not in the template)Registering plugins
Use this stage only when template-level handling isn't possible.
Metadata Priority (highest to lowest)
metadataOverride— forces values regardless of user settingsformat.metadata— user values + normalization fromrevealResolveFormat()Pandoc
defField— Pandoc writer defaults for unset variablesextras.metadata— Quarto's opinionated defaults
Template Type Handling
Pandoc templates render values as text. This creates type mismatches when reveal.js expects specific JavaScript types. Quarto's template.html uses conditional guards to render correct JS types.
The Problem
Pandoc template variables have limited type awareness:
$var$rendersBoolVal Trueastrue,BoolVal Falseasfalse(correct for JS booleans)'$var$'always renders as a quoted string, even forfalse→'false'(wrong — truthy in JS)Numbers rendered inside quotes become strings:
'$var$'with0→'0'(wrong if JS expects a number)
Pattern: Mixed-Type Options
When an option accepts both strings and booleans (e.g., scrollSnap: "mandatory" | "proximity" | false):
This works because Pandoc's $if()$ evaluates BoolVal False as false, so:
String values (
"mandatory","proximity") →$if$is true → quoted outputBoolean
false→$if$is false →$else$renders unquotedfalse
Pattern: String "auto" with Boolean Fallback
When an option accepts "auto" | true | false (e.g., scrollProgress), a helper flag avoids rendering "auto" as a boolean:
TypeScript (normalization stage):
Template:
Pattern: Numeric Options
When reveal.js checks typeof value === 'number', the template must NOT quote the value:
Not '$scrollActivationWidth$' — that renders as string '0' instead of number 0.
Known Pandoc Template Issues
Pandoc's upstream revealjs.template (copied to revealjs.template) has type issues in the scroll-view block that Quarto's template.html fixes. Tracked in jgm/pandoc#11486:
scrollSnap: '$scrollSnap$'rendersfalseas string'false'(truthy in JS)scrollActivationWidth: '$scrollActivationWidth$'renders numbers as stringsscrollProgressdefField defaults totrueinstead of reveal.js's'auto'
Adding New Reveal.js Options
When adding support for a new reveal.js configuration option:
Add the constant to
constants.tsIf the option needs YAML normalization (e.g., a compound structure), add to
revealResolveFormat()If the option needs a default value, add to
extras.metadatainformatExtras()If the option needs type-safe rendering, add to
template.htmlwith appropriate$if/$else$guardsIf the option can only be handled post-render, add to
extraConfig(last resort)Add smoke-all tests covering type edge cases