Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

reveal.js -- Administrator & Developer Guide

Generated May 2026 from hakimel/reveal.js at 76dc900

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

reveal.js v6.0.1 is a JavaScript presentation framework that transforms semantic HTML into fully interactive slide decks with transitions, fragments, speaker notes, code highlighting, math rendering, and more. This guide covers every architectural detail, configuration option, and operational concern an administrator or developer needs to deploy, extend, customize, and maintain reveal.js presentations at any scale.

For installation walkthroughs, everyday usage, and feature tutorials, see the User Guide.


1. Architecture Overview

1.1 Design Philosophy

reveal.js uses a closure-based factory pattern rather than ES6 classes. The main entry point (js/reveal.js) exports a factory function that returns a Reveal object. Each presentation instance is a self-contained closure with private state and a public API surface. This enables multiple independent presentations on a single page without shared mutable state.

The framework has zero runtime dependencies. Every dependency in package.json is a devDependency used only during build time. The distributed bundle is fully self-contained.

1.2 Entry Point and Initialization Flow

The initialization sequence proceeds through these stages:

  1. Factory invocation -- Reveal() or new Reveal() creates a presentation instance
  2. Config merge -- defaultConfig from js/config.ts is merged with constructor options
  3. DOM validation -- locates the .reveal root element (throws "Unable to find presentation root (<div class="reveal">)" if missing)
  4. Controller instantiation -- all 20 internal controllers are created
  5. Plugin registration -- plugins from config.plugins array are registered
  6. Plugin initialization -- all plugins' init() methods are called and awaited
  7. Layout -- initial layout calculation and slide positioning
  8. ready event -- fires only after all plugins have initialized

Important

The ready event is the only safe point to begin interacting with the API programmatically. Code that runs before ready may encounter uninitialized plugins or incomplete DOM state.

1.3 Controller Inventory

Every controller is instantiated during initialization and manages a specific aspect of the presentation. Controllers communicate through the central Reveal instance and its event system.

Controller Source File Responsibility
SlideContent js/controllers/slidecontent.js Lazy-loading of slide content, media lifecycle (play/pause/stop), iframe management, preloading based on viewDistance
SlideNumber js/controllers/slidenumber.js Slide number rendering in configurable formats (h.v, h/v, c, c/t)
JumpToSlide js/controllers/jumptoslide.js Jump-to-slide overlay triggered by G key, accepts slide number or h.v format
Backgrounds js/controllers/backgrounds.js Creates and synchronizes .slide-background elements for images, videos, iframes, gradients, and solid colors
AutoAnimate js/controllers/autoanimate.js FLIP-based animation between consecutive data-auto-animate slides, element matching by data-id or DOM heuristics
ScrollView js/controllers/scrollview.js Scroll-based view mode as alternative to slide-by-slide navigation
PrintView js/controllers/printview.js PDF-optimized layout for print/export workflows
Fragments js/controllers/fragments.js Fragment stepping, ordering, grouping, and state management
Overview js/controllers/overview.js Bird's-eye view of all slides (activated by ESC or O key)
Keyboard js/controllers/keyboard.js Keyboard shortcut registration, dispatch, and custom binding management
Location js/controllers/location.js URL hash reading/writing, history API integration, deep linking
Controls js/controllers/controls.js Navigation arrow rendering, tutorial animation, directional availability
Progress js/controllers/progress.js Progress bar rendering and click-to-navigate
Pointer js/controllers/pointer.js Cursor visibility management, auto-hide after hideCursorTime
Plugins js/controllers/plugins.js Plugin registration, initialization sequencing, lifecycle management
Overlay js/controllers/overlay.js Link preview overlays for iframes, images, and videos
Touch js/controllers/touch.js Touch and swipe gesture recognition for mobile navigation
Focus js/controllers/focus.js Focus state management and accessibility
Notes js/controllers/notes.js Internal notes state tracking for <aside class="notes"> and data-notes
Playback js/components/playback.js Canvas-based play/pause UI for auto-slide timer

1.4 Module Dependency Graph

reveal.js (factory)
  +-- config.ts (defaults + RevealConfig interface)
  +-- controllers/ (20 controllers)
  |     +-- plugins.js --> plugin instances
  |     +-- slidecontent.js --> utils/loader.ts
  |     +-- autoanimate.js --> utils/util.ts
  |     +-- location.js --> utils/util.ts (getQueryHash)
  |     +-- backgrounds.js --> utils/color.ts
  +-- utils/
  |     +-- color.ts (colorToRgb, colorBrightness)
  |     +-- constants.ts (selectors, blacklists, regex)
  |     +-- device.ts (isMobile, isChrome, isAndroid)
  |     +-- loader.ts (dynamic script/link injection)
  |     +-- util.ts (DOM helpers, math, serialization)
  +-- components/
        +-- playback.js (canvas UI)

1.5 Utility Modules

Module Exports Purpose
js/utils/color.ts colorToRgb(), colorBrightness() Parse CSS color strings and compute brightness for light/dark background detection
js/utils/constants.ts SLIDES_SELECTOR, POST_MESSAGE_METHOD_BLACKLIST, FRAGMENT_STYLE_REGEX, slide number format constants Centralized selectors and security constants
js/utils/device.ts isMobile, isChrome, isAndroid User-agent based device detection for touch/rendering behavior
js/utils/loader.ts loadScript() Dynamic <script> injection with callback
js/utils/util.ts extend(), queryAll(), toggleClass(), deserialize(), distanceBetween(), transformElement(), matches(), closest(), enterFullscreen(), createSingletonNode(), createStyleSheet(), getQueryHash(), getRemainingHeight(), getMimeTypeFromFile(), encodeRFC3986URI() DOM manipulation, math, serialization, fullscreen API

2. System Requirements

2.1 Build Environment

Requirement Minimum Version
Node.js >= 20.19.0 (enforced in package.json engines field)
npm Bundled with Node.js 20+

2.2 Build Toolchain (devDependencies)

All dependencies are development-only. The built output has zero runtime dependencies.

Package Version Role
TypeScript ^6.0.2 Type checking and declaration generation
Vite ^8.0.3 Build system and dev server
esbuild ^0.28.0 ES5 fallback transpilation
Sass ^1.98.0 SCSS theme compilation
vite-plugin-dts ^4.5.4 TypeScript declaration file generation
highlight.js ^11.11.1 Bundled into Highlight plugin
marked ^17.0.5 Bundled into Markdown plugin
marked-smartypants ^1.1.11 Smart quotes for Markdown plugin
fitty ^2.4.2 Text fitting utility
jszip ^3.10.1 ZIP archive creation for npm run package
glob ^13.0.6 File globbing for build scripts
QUnit ^2.25.0 Test framework
node-qunit-puppeteer ^2.2.1 Headless browser test runner

2.3 Browser Support

reveal.js targets modern browsers with ES module support. The npm run build:es5 command produces an ES5 fallback bundle via esbuild for legacy environments.

Browser Support
Chrome/Edge Current and recent versions
Firefox Current and recent versions
Safari Current and recent versions
Mobile Safari/Chrome Supported with touch gestures
IE 11 ES5 fallback only (reveal.es5.js)

Note

Device detection in js/utils/device.ts applies browser-specific workarounds. The isChrome and isAndroid flags affect touch handling and rendering behavior.

2.4 React Wrapper Requirements

The @revealjs/react package (v0.2.1) in react/ has these peer dependencies:

Package Version
react >= 18
react-dom >= 18
reveal.js >= 5

3. Configuration Reference

3.1 Config Resolution Order

Configuration values are merged with increasing precedence:

  1. defaultConfig -- hardcoded defaults in js/config.ts
  2. Reveal.configure() calls before initialize() -- pre-init overrides
  3. Constructor options -- Reveal({ ... }) or new Reveal({ ... })
  4. Reveal.initialize() options -- final programmatic overrides
  5. URL query parameters -- parsed by getQueryHash() from the URL fragment

Tip

URL query parameters provide an easy way to override config for testing or sharing. Append them after # in the URL: presentation.html#/2?transition=none&controls=false. Values are automatically deserialized (strings "true"/"false" become booleans, numeric strings become numbers).

3.2 Complete Config Options

Every option below is from the defaultConfig object in js/config.ts and the RevealConfig interface.

3.2.1 Presentation Dimensions

Option Type Default Description
width number 960 Presentation width in pixels. The framework scales content to fit the viewport while maintaining this aspect ratio.
height number 700 Presentation height in pixels.
margin number 0.04 Factor of empty space around the content (0.0 = no margin, 0.5 = half the viewport).
minScale number 0.2 Minimum scale factor applied to the presentation.
maxScale number 2.0 Maximum scale factor applied to the presentation.

3.2.2 Controls

Option Type Default Description
controls boolean true Show navigation arrow controls.
controlsTutorial boolean true Show a subtle bounce animation on controls the first time a presentation is viewed to hint at interactivity.
controlsLayout string 'bottom-right' Position of controls. Allowed values: 'bottom-right', 'edges'.
controlsBackArrows string 'faded' Visibility of back-direction arrows. Allowed values: 'faded', 'hidden', 'visible'.

3.2.3 Progress and Slide Numbers

Option Type Default Description
progress boolean true Show a thin progress bar at the bottom.
slideNumber boolean | string false Display slide number. Set to true for default format, or a format string: 'h.v' (horizontal.vertical), 'h/v', 'c' (flattened count), 'c/t' (count/total).
showSlideNumber string 'all' Where slide numbers appear. Allowed values: 'all', 'print', 'speaker'.

3.2.4 Navigation and History

Option Type Default Description
hash boolean false Write the current slide hash to the URL, enabling browser back/forward navigation.
hashOneBasedIndex boolean false Use 1-based indices in URL hash instead of 0-based.
respondToHashChanges boolean true Listen for hashchange events and navigate accordingly.
jumpToSlide boolean true Enable the jump-to-slide overlay (triggered by G key).
history boolean false Push each slide change to the browser history (creates back/forward entries).
keyboard boolean true Enable keyboard navigation shortcuts.
keyboardCondition string | null | function null Condition for keyboard activation. Set to 'focused' to only enable when the presentation has focus. Can also be a function returning boolean.
overview boolean true Enable the slide overview mode (ESC/O key).
loop boolean false Loop the presentation (navigating past the last slide returns to the first).
rtl boolean false Right-to-left navigation order.
navigationMode string 'default' Navigation mode. Allowed values: 'default', 'linear', 'grid'. Linear flattens all slides. Grid enables full 2D arrow navigation.
shuffle boolean false Randomize slide order on each presentation load.

3.2.5 Content Behavior

Option Type Default Description
center boolean true Vertically center slide content.
touch boolean true Enable touch/swipe navigation on touch devices.
fragments boolean true Enable fragment stepping (sequential reveal of elements).
fragmentInURL boolean true Include fragment index in the URL hash.
help boolean true Enable the help overlay (? key).
pause boolean true Enable pause mode (. or B key).
showNotes boolean false Show speaker notes in the presentation view (visible to audience).
showHiddenSlides boolean false Show slides marked with data-visibility="hidden".
sortFragmentsOnSync boolean true Automatically sort fragments by their data-fragment-index on sync.

3.2.6 Media and Embedding

Option Type Default Description
autoPlayMedia boolean | null null Auto-play <video> and <audio> on slide entry. null = auto-play only elements with autoplay attribute. true = always. false = never.
preloadIframes boolean | null null Pre-load <iframe> content. null = preload only elements with data-preload. true = always. false = never.
previewLinks boolean false Open links in an iframe overlay instead of navigating away.
viewDistance number 3 Number of slides away from current to pre-load content for.
mobileViewDistance number 2 Same as viewDistance but for mobile devices (reduced for performance).

3.2.7 Appearance

Option Type Default Description
display string 'block' CSS display value applied to each slide when shown.
hideInactiveCursor boolean true Hide the cursor after a period of inactivity.
hideCursorTime number 5000 Milliseconds before an inactive cursor is hidden.
embedded boolean false Mark the presentation as embedded within a larger page (affects sizing/layout).
disableLayout boolean false Disable all reveal.js layout/scaling. Useful for fully custom CSS layouts.

3.2.8 Auto-Animate

Option Type Default Description
autoAnimate boolean true Enable auto-animate between consecutive slides with data-auto-animate.
autoAnimateMatcher function | null null Custom element matching function for auto-animate. Signature: (fromEl, toEl) => boolean.
autoAnimateEasing string 'ease' Default CSS easing for auto-animate transitions.
autoAnimateDuration number 1.0 Default duration in seconds for auto-animate transitions.
autoAnimateUnmatched boolean true Animate unmatched elements (fade in/out) during auto-animate.
autoAnimateStyles string[] ['opacity', 'color', 'background-color', 'padding', 'font-size', 'line-height', 'letter-spacing', 'border-width', 'border-color', 'border-radius', 'outline', 'outline-offset'] CSS properties that are auto-animated when they differ between matched elements.

3.2.9 Auto-Slide

Option Type Default Description
autoSlide number 0 Milliseconds between automatic slide transitions. 0 disables.
autoSlideStoppable boolean true Allow the user to stop auto-sliding by interacting with the presentation.
autoSlideMethod function | null null Custom function called to advance slides during auto-slide. Receives the Reveal instance.
defaultTiming number | null null Default timing for slides without data-autoslide. If set, used instead of autoSlide per slide.

3.2.10 Transitions

Option Type Default Description
transition string 'slide' Default slide transition. Allowed values: 'none', 'fade', 'slide', 'convex', 'concave', 'zoom'.
transitionSpeed string 'default' Transition speed. Allowed values: 'default', 'fast', 'slow'.
backgroundTransition string 'fade' Background transition style. Same allowed values as transition.

3.2.11 Parallax Backgrounds

Option Type Default Description
parallaxBackgroundImage string '' URL of parallax background image.
parallaxBackgroundSize string '' CSS background-size for parallax image (e.g., '2100px 900px').
parallaxBackgroundRepeat string '' CSS background-repeat for parallax image.
parallaxBackgroundPosition string '' CSS background-position for parallax image.
parallaxBackgroundHorizontal number | null null Pixels to shift parallax background per slide horizontally. Auto-calculated if null.
parallaxBackgroundVertical number | null null Pixels to shift parallax background per slide vertically. Auto-calculated if null.

3.2.12 Scroll View

Option Type Default Description
view string | null null View mode. Set to 'scroll' for scroll-based presentation. null for default slide view.
scrollLayout string 'full' Scroll view layout. Allowed values: 'full', 'compact'.
scrollSnap string 'mandatory' CSS scroll-snap behavior. Allowed values: 'mandatory', 'proximity'.
scrollProgress string 'auto' Show scroll progress indicator. Allowed values: 'auto', true, false.
scrollActivationWidth number 435 Viewport width threshold (in pixels) below which scroll view is automatically activated.

3.2.13 PDF Export

Option Type Default Description
pdfMaxPagesPerSlide number Infinity Maximum number of PDF pages generated per slide (for very tall slides). Infinity means no limit.
pdfSeparateFragments boolean true Give each fragment step its own page in the PDF.
pdfPageHeightOffset number -1 Offset applied to PDF page height to avoid page-break issues. -1 uses auto-detection.

3.2.14 Plugins and PostMessage

Option Type Default Description
plugins array [] Array of plugin instances or factory functions to register.
dependencies array [] Legacy dependency loading (deprecated in favor of plugins).
postMessage boolean true Enable the postMessage API for cross-window communication.
postMessageEvents boolean false Dispatch all reveal.js events as postMessage messages to the parent window.
focusBodyOnPageVisibilityChange boolean true Focus document.body when the page becomes visible (prevents focus loss).
preventIframeAutoFocus boolean false Prevent iframe embeds from automatically stealing focus.

3.3 Plugin-Specific Config Keys

Plugin configuration is nested under the main config object using the plugin name as the key.

3.3.1 Highlight Plugin Config

Reveal.initialize({
  highlight: {
    highlightOnLoad: true,    // boolean - Auto-highlight <pre><code> on load
    escapeHTML: true,          // boolean - Escape HTML entities in code blocks
    beforeHighlight: null      // function(code, block) - Callback before highlighting
  }
});

3.3.2 Markdown Plugin Config

Reveal.initialize({
  markdown: {
    separator: '\\r?\\n---\\r?\\n',       // string - Horizontal slide separator regex
    verticalSeparator: null,               // string|null - Vertical slide separator regex
    notesSeparator: '^\\s*notes?:',        // string - Notes separator regex
    animateLists: false,                   // boolean - Wrap <li> elements in fragments
    smartypants: false,                    // boolean - Enable typographic quote replacement
    // All marked library options are also accepted:
    gfm: true,                            // boolean - GitHub Flavored Markdown
    breaks: false,                         // boolean - Treat newlines as <br>
    renderer: null                         // object - Custom marked renderer
  }
});

3.3.3 Math Plugin Config (KaTeX)

Reveal.initialize({
  katex: {
    local: null,              // string|null - Path to local KaTeX installation
    version: 'latest',        // string - KaTeX version from CDN
    delimiters: [             // array - Delimiter pairs for math detection
      { left: '$$', right: '$$', display: true },
      { left: '$', right: '$', display: false },
      { left: '\\(', right: '\\)', display: false },
      { left: '\\[', right: '\\]', display: true }
    ],
    ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
    extensions: []            // array - KaTeX extensions (e.g., ['mhchem'])
  }
});

CDN base: cdn.jsdelivr.net/npm/katex

3.3.4 Math Plugin Config (MathJax2)

Reveal.initialize({
  mathjax2: {
    mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js',
    config: 'TeX-AMS_HTML-full',    // string - MathJax configuration preset
    tex2jax: {
      inlineMath: [['$', '$'], ['\\(', '\\)']],
      skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
    }
  }
});

MathJax2 retypesets on every slidechanged event.

3.3.5 Math Plugin Config (MathJax3)

Reveal.initialize({
  mathjax3: {
    mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
    tex: {
      inlineMath: [['$', '$'], ['\\(', '\\)']]
    },
    options: {
      skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
    },
    startup: {
      ready: null              // function - Custom startup handler
    }
  }
});

Sets window.MathJax configuration object before loading the library.

3.3.6 Math Plugin Config (MathJax4)

Reveal.initialize({
  mathjax4: {
    mathjax: 'https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js',
    tex: {
      inlineMath: [['$', '$'], ['\\(', '\\)']]
    },
    options: {
      skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre']
    },
    startup: {
      ready: null
    },
    output: 'chtml'            // string - Output format
  }
});

Uses async startup and waits for MathJax.startup.promise to resolve.


4. Deployment & Scaling

4.1 Build Commands

Command Purpose Output
npm run dev / npm start Start Vite dev server with hot reload Serves from source
npm run build Full production build (TypeScript + Vite core + styles + all 6 plugins) dist/
npm run build:core Build core library only dist/reveal.js, dist/reveal.mjs, dist/reveal.d.ts
npm run build:es5 ES5 fallback bundle via esbuild dist/reveal.es5.js
npm run build:styles Compile SCSS themes and base styles dist/reveal.css, dist/reset.css, dist/theme/*.css
npm run package Create distributable ZIP archive ZIP file via jszip
npm test Run QUnit tests in headless Puppeteer Console output
npm run react:build Build React wrapper react/dist/
npm run react:demo Run React wrapper demo Dev server
npm run react:test Run React wrapper tests (Vitest + Testing Library) Console output

4.2 Build Architecture

Each plugin has its own vite.config.ts that produces both ES module (.mjs) and UMD (.js) formats. TypeScript declarations are generated via vite-plugin-dts with a custom path rewriting plugin at plugin/vite-plugin-dts.ts.

The build pipeline:

TypeScript compile (tsc)
  +-- Vite build: core (js/index.ts -> dist/reveal.{js,mjs})
  +-- Vite build: highlight plugin (-> dist/plugin/highlight.{js,mjs})
  +-- Vite build: markdown plugin (-> dist/plugin/markdown.{js,mjs})
  +-- Vite build: math plugin (-> dist/plugin/math.{js,mjs})
  +-- Vite build: notes plugin (-> dist/plugin/notes.{js,mjs})
  +-- Vite build: search plugin (-> dist/plugin/search.{js,mjs})
  +-- Vite build: zoom plugin (-> dist/plugin/zoom.{js,mjs})
  +-- Sass compile: themes (css/theme/*.scss -> dist/theme/*.css)
  +-- Sass compile: base (css/reveal.scss -> dist/reveal.css)
  +-- Copy: reset.css -> dist/reset.css

4.3 Package Exports Map

The package.json exports field defines the public module entry points:

Specifier CJS ESM Types
. dist/reveal.js dist/reveal.mjs dist/reveal.d.ts
./reveal.css dist/reveal.css -- --
./reset.css dist/reset.css -- --
./theme/* dist/theme/* -- --
./plugin/highlight dist/plugin/highlight.js dist/plugin/highlight.mjs dist/plugin/highlight.d.ts
./plugin/markdown dist/plugin/markdown.js dist/plugin/markdown.mjs dist/plugin/markdown.d.ts
./plugin/math dist/plugin/math.js dist/plugin/math.mjs dist/plugin/math.d.ts
./plugin/notes dist/plugin/notes.js dist/plugin/notes.mjs dist/plugin/notes.d.ts
./plugin/search dist/plugin/search.js dist/plugin/search.mjs dist/plugin/search.d.ts
./plugin/zoom dist/plugin/zoom.js dist/plugin/zoom.mjs dist/plugin/zoom.d.ts

4.4 Deployment Patterns

Static File Hosting

The simplest deployment is serving the dist/ directory (plus your HTML files) from any static host (Nginx, Apache, S3, Netlify, Vercel, GitHub Pages).

your-presentation/
  index.html
  dist/
    reveal.js
    reveal.mjs
    reveal.css
    reset.css
    theme/
    plugin/

CDN Usage

Warning

As of v6.0.1, CDN availability is a known issue (see GitHub issue #3894). Verify the version is available on your CDN of choice before relying on it for production.

npm Package

import Reveal from 'reveal.js';
import 'reveal.js/reveal.css';
import 'reveal.js/theme/black.css';
import Highlight from 'reveal.js/plugin/highlight';
import Markdown from 'reveal.js/plugin/markdown';

Self-Hosted with Vite Dev Server

For development, npm run dev starts Vite with hot module replacement. The index.html at the project root serves as the development entry point.

4.5 Multiple Instances

reveal.js supports multiple independent presentation instances on a single page. Each Reveal() call creates a new instance targeting a different .reveal root element:

let deck1 = new Reveal(document.querySelector('#deck1'), { embedded: true });
let deck2 = new Reveal(document.querySelector('#deck2'), { embedded: true });

await deck1.initialize();
await deck2.initialize();

Set embedded: true to prevent instances from capturing global keyboard events.

Caution

When running multiple instances, each must target a unique DOM element. Initializing two instances on the same .reveal root leads to undefined behavior. The embedded: true flag is essential to prevent keyboard/focus conflicts.


5. Operations

5.1 Theme System

reveal.js ships 14 themes, all authored as SCSS in css/theme/:

Theme File Character
beige beige.scss Warm, parchment-like
black black.scss Dark, high contrast (default)
black-contrast black-contrast.scss WCAG-enhanced dark
blood blood.scss Dark red dramatic
dracula dracula.scss Dracula color scheme
league league.scss Dark gray textured
moon moon.scss Dark blue/gray
night night.scss Pure dark
serif serif.scss Light, serif typography
simple simple.scss Minimal light
sky sky.scss Light blue
solarized solarized.scss Solarized light palette
white white.scss Clean white
white-contrast white-contrast.scss WCAG-enhanced light

Theme Architecture

The theme template system uses three files in css/theme/template/:

  • settings.scss -- Defines all SCSS variables (fonts, colors, spacing, heading sizes)
  • mixins.scss -- Shared SCSS mixins
  • theme.scss -- Base theme styles that consume the variables

Each theme file imports the template, overrides variables, and optionally adds custom rules. To create a custom theme:

// my-theme.scss
@use 'template/settings' with (
  $backgroundColor: #191919,
  $mainColor: #fff,
  $headingColor: #fff,
  $linkColor: #42affa
);
@use 'template/theme';

5.2 PDF Export

PDF export works through the PrintView controller. Access the print-optimized layout by appending ?print-pdf to the URL, then use the browser's print dialog (Ctrl/Cmd+P).

Key config options:

  • pdfSeparateFragments: true -- each fragment step gets its own page
  • pdfMaxPagesPerSlide: Infinity -- limit pages for very tall slides
  • pdfPageHeightOffset: -1 -- auto-detect page height offset

The pdf-ready event fires when the print layout is fully rendered and ready for capture.

Note

GitHub issue #3860 reports that PDF export can generate very large files. Issue #3888 documents compatibility problems with Decktape (a popular third-party PDF export tool). For reliable PDF export, use the browser's native print dialog with Chrome.

5.3 Keyboard Shortcuts

Default key bindings registered by the Keyboard controller:

Key Action
Right / Down / Space / N / Page Down Next slide
Left / Up / Shift+Space / P / Page Up Previous slide
Home First slide
End Last slide
F Toggle fullscreen
ESC / O Toggle overview
S Open speaker notes window
G Jump to slide overlay
? Toggle help overlay
. / B Toggle pause (blackout)
V Toggle black screen

5.4 Events Reference

All events are dispatched via the reveal.js event system and can be listened to with Reveal.on():

Event Payload Fires When
ready { indexh, indexv, currentSlide } Initialization complete, all plugins loaded
slidechanged { indexh, indexv, previousSlide, currentSlide, origin } Slide navigation occurs
slidesync { indexh, indexv, currentSlide } Slide content synchronized
fragmentshown { fragment, fragments } Fragment becomes visible
fragmenthidden { fragment, fragments } Fragment becomes hidden
overviewshown {} Overview mode activated
overviewhidden {} Overview mode deactivated
paused {} Presentation paused
resumed {} Presentation resumed
autoanimate { fromSlide, toSlide } Auto-animate transition occurs
pdf-ready {} Print/PDF layout fully rendered
previewiframe { url } Iframe preview overlay shown
previewimage { url } Image preview overlay shown
previewvideo { url } Video preview overlay shown
closeoverlay {} Preview overlay closed

6. Performance

6.1 Lazy Loading

The SlideContent controller implements lazy loading based on viewDistance (default: 3 slides) and mobileViewDistance (default: 2). Content outside the view distance is not loaded until the user navigates near it.

This affects:

  • <img> with data-src -- source set on approach, cleared on departure
  • <video> and <audio> with data-src -- source set on approach
  • <iframe> with data-src -- source set on approach, cleared on departure
  • Background images, videos, and iframes follow the same pattern

6.2 Layout Performance

  • layout() recalculates all slide positions and scaling. Called automatically on window resize.
  • sync() re-processes all slides (content, backgrounds, fragments). Expensive; use syncSlide() for single-slide updates.
  • disableLayout: true skips all reveal.js layout calculations, deferring entirely to CSS.
  • Background brightness detection (colorBrightness() in utils/color.ts) adds has-light-background or has-dark-background classes, enabling automatic text color adaptation.

6.3 Mobile Optimization

  • mobileViewDistance reduces preloading on mobile to conserve bandwidth and memory
  • Touch controller uses passive event listeners where supported
  • Device detection (utils/device.ts) adjusts behavior for mobile browsers
  • scrollActivationWidth: 435 auto-activates scroll view on narrow viewports

Tip

For bandwidth-constrained deployments, reduce viewDistance and mobileViewDistance to 1. This significantly reduces upfront resource loading at the cost of brief loading delays during navigation.


7. Security

7.1 PostMessage API Security

The postMessage API enables cross-window communication (used by the speaker notes window and embedded presentations). Security measures:

Method Blacklist (POST_MESSAGE_METHOD_BLACKLIST in js/utils/constants.ts):

The following methods are blocked from postMessage invocation to prevent unauthorized plugin injection, event hijacking, and preview abuse:

  • registerPlugin
  • registerKeyboardShortcut
  • addKeyBinding
  • addEventListener
  • showPreview
  • previewIframe

Any postMessage attempting to call these methods is silently ignored.

7.2 Speaker Notes Window Security

The Notes plugin implements same-origin verification on postMessage events. Only messages from the same origin (window.location.origin) are accepted. This XSS safeguard prevents malicious cross-origin pages from injecting commands into the speaker view.

The notes window uses a heartbeat mechanism for orphaned window reconnection -- if the parent window closes and reopens, the existing notes window can re-establish the connection.

7.3 Query Parameter Sanitization

The getQueryHash() function in js/utils/util.ts explicitly deletes the dependencies key from parsed URL query parameters. This prevents script injection via crafted URLs that could load arbitrary remote scripts through the legacy dependency system.

7.4 Markdown External File Loading

External markdown files loaded via <section data-markdown="file.md"> use XHR requests, which are subject to the browser's same-origin policy. Cross-origin markdown files require appropriate CORS headers on the serving host.

Warning

When postMessage: true (the default), any page that can reference your presentation's window can send navigation commands. Set postMessage: false for presentations containing sensitive content that should not be externally controllable.

7.5 Content Security Policy Considerations

reveal.js dynamically creates <style> elements (via createStyleSheet() in utils/util.ts) and injects inline styles for layout. A strict CSP policy requires:

  • style-src 'unsafe-inline' -- for dynamic style injection
  • script-src must allow the reveal.js bundle and any plugin scripts
  • frame-src as needed for iframe backgrounds and preview overlays
  • Math plugins load scripts from cdn.jsdelivr.net by default; either allow this origin or use the local config option

8. Developer Internals

8.1 Plugin Architecture

Plugin Interface

interface RevealPlugin {
  id: string;                              // Unique identifier
  init?(reveal: RevealApi): void | Promise<void>;  // Called during initialization
  destroy?(): void;                        // Called on Reveal.destroy()
}

Plugins can also be registered as factory functions that return a RevealPlugin object:

// Factory pattern
const MyPlugin = () => ({
  id: 'my-plugin',
  init: (reveal) => {
    // Access full API
    reveal.on('slidechanged', handleSlideChange);
    reveal.getConfig(); // read config
  },
  destroy: () => {
    // Cleanup
  }
});

Reveal.initialize({
  plugins: [MyPlugin]
});

Plugin Lifecycle

  1. Registration -- plugins are registered from config.plugins array or via Reveal.registerPlugin(plugin)
  2. Initialization -- Plugins controller calls each plugin's init() method, passing the RevealApi instance
  3. Async support -- if init() returns a Promise, the framework waits for all plugin promises to resolve before firing ready
  4. Access -- Reveal.hasPlugin(id), Reveal.getPlugin(id), Reveal.getPlugins() for runtime inspection
  5. Destruction -- Reveal.destroy() calls each plugin's destroy() method

Built-in Plugin Details

Highlight (id: 'highlight')

  • Wraps highlight.js for syntax highlighting
  • Processes all <pre><code> blocks in the presentation
  • data-line-numbers attribute format: "1,2|3,5-10" where | separates animation steps, , separates individual lines, - denotes ranges
  • data-trim normalizes leading/trailing whitespace
  • data-noescape prevents HTML entity escaping
  • data-fragment-index controls fragment ordering when line highlighting steps

Markdown (id: 'markdown')

  • Wraps marked library with marked-smartypants extension
  • Two authoring modes:
    • Inline: <section data-markdown> with <script type="text/template"> or <textarea data-template>
    • External: <section data-markdown="file.md"> loads via XHR
  • Attribute injection via HTML comments:
    • Element: <!-- .element: class="fragment" data-fragment-index="1" -->
    • Slide: <!-- .slide: data-background="#ff0000" -->
  • Default separators: horizontal \r?\n---\r?\n, vertical null, notes ^\s*notes?:

Math (wrapper, id depends on sub-plugin)

  • Contains 4 sub-plugins: KaTeX (id: 'katex'), MathJax2 (id: 'mathjax2'), MathJax3 (id: 'mathjax3'), MathJax4 (id: 'mathjax4')
  • MathJax2 is the default if Math is registered without specifying a sub-plugin
  • Each sub-plugin loads its library from CDN by default but supports local paths

Notes (id: 'notes')

  • Opens speaker view in a popup window (triggered by S key, keyCode 83)
  • Communication via postMessage with same-origin check
  • Notes sources (in priority order): fragment-level notes override slide-level
    • <aside class="notes"> elements
    • data-notes attribute on <section>
  • Heartbeat for orphaned window reconnection

Search (id: 'search')

  • Registers Ctrl+Shift+F keyboard shortcut
  • Uses Hilitor algorithm for DOM-based text highlighting
  • Highlight colors cycle: #ff6, #a0ffff, #9f9, #f99, #f6f
  • Methods: open(), close(), toggle()
  • Input field appears top-right, Enter advances to next match

Zoom (id: 'zoom')

  • Alt+Click to zoom (Ctrl+Click on Linux)
  • Config: zoomKey (override modifier key), zoomLevel (default: 2)
  • Escape to zoom out
  • CSS transform-based with mouse-tracking pan support
  • Methods: zoom.to(), zoom.out(), zoom.magnify(), zoom.reset(), zoom.zoomLevel()

8.2 Public API Reference

The complete public API as defined in reveal.d.ts:

Initialization and Lifecycle

Method Signature Description
initialize (options?: RevealOptions) => Promise<RevealApi> Initialize the presentation. Returns a promise that resolves when ready.
configure (options: RevealOptions) => void Update configuration at runtime. Triggers re-layout.
destroy () => void Destroy the instance, remove event listeners, clean up DOM.
sync () => void Re-process all slides (content, backgrounds, fragments, notes).
syncSlide (slide?: HTMLElement) => void Re-process a single slide.
syncFragments (slide?: HTMLElement) => void Re-process fragments on a slide.
Method Signature Description
slide (h: number, v?: number, f?: number) => void Navigate to specific slide by indices (horizontal, vertical, fragment).
left () => void Navigate left.
right () => void Navigate right.
up () => void Navigate up.
down () => void Navigate down.
prev () => void Navigate to previous slide.
next () => void Navigate to next slide.
prevFragment () => boolean Step to previous fragment. Returns false if no previous fragment.
nextFragment () => boolean Step to next fragment. Returns false if no next fragment.
navigateFragment (index: number) => void Navigate to a specific fragment index.
shuffle () => void Randomize slide order.

State

Method Signature Description
getState () => RevealState Get current presentation state (indices, paused, overview).
setState (state: RevealState) => void Restore a previously captured state.
getProgress () => number Get progress through presentation (0.0 to 1.0).
getIndices (slide?: HTMLElement) => { h: number, v: number, f: number } Get indices of current or specified slide.
getScale () => number Get current scale factor.
getConfig () => RevealOptions Get active configuration.

Slide Access

Method Signature Description
getSlides () => HTMLElement[] Get all slide elements as a flat array.
getSlide (x: number, y?: number) => HTMLElement Get slide element at given indices.
getCurrentSlide () => HTMLElement Get current slide element.
getPreviousSlide () => HTMLElement Get previous slide element.
getTotalSlides () => number Get total number of slides.
getSlidePastCount () => number Get number of slides before current.
getSlideNotes (slide?: HTMLElement) => string Get notes for current or specified slide.
getSlideBackground (x: number, y?: number) => HTMLElement Get background element for slide at given indices.

Queries

Method Signature Description
isReady () => boolean True after initialization completes.
isPaused () => boolean True if presentation is paused.
isOverview () => boolean True if overview mode is active.
isFirstSlide () => boolean True if on the first slide.
isLastSlide () => boolean True if on the last slide.
availableRoutes () => { left: boolean, right: boolean, up: boolean, down: boolean } Check which navigation directions are available.
availableFragments () => { prev: boolean, next: boolean } Check if previous/next fragments exist.

Toggles

Method Signature Description
toggleHelp (override?: boolean) => void Toggle or set help overlay visibility.
toggleOverview (override?: boolean) => void Toggle or set overview mode.
togglePause (override?: boolean) => void Toggle or set pause state.
toggleAutoSlide (override?: boolean) => void Toggle or set auto-slide.
layout () => void Force a layout recalculation.

Plugins

Method Signature Description
registerPlugin (plugin: RevealPlugin) => void Register a plugin at runtime.
hasPlugin (id: string) => boolean Check if a plugin is registered.
getPlugin (id: string) => RevealPlugin Get a registered plugin by ID.
getPlugins () => { [id: string]: RevealPlugin } Get all registered plugins.

Keyboard

Method Signature Description
addKeyBinding (binding: object, callback: function) => void Register a custom key binding.
removeKeyBinding (keyCode: number) => void Remove a key binding.
triggerKey (keyCode: number) => void Programmatically trigger a key press.
registerKeyboardShortcut (key: string, description: string) => void Register a shortcut for the help overlay.

Events

Method Signature Description
on (type: string, listener: function, options?: object) => void Add event listener.
off (type: string, listener: function, options?: object) => void Remove event listener.
dispatchEvent (event: Event) => void Dispatch a custom event.

Preview

Method Signature Description
showPreview (url: string) => void Show a URL in the preview overlay.
hidePreview () => void Hide the preview overlay.

8.3 Data Attributes Reference

Slide-Level Attributes

Attribute Values Description
data-transition none, fade, slide, convex, concave, zoom Per-slide transition override. Supports directional: slide-in fade-out.
data-transition-speed default, fast, slow Per-slide transition speed.
data-autoslide integer (ms) Per-slide auto-advance timing.
data-notes string Speaker notes for the slide.
data-visibility hidden, uncounted Hide slide from navigation (hidden) or exclude from count (uncounted).
data-state string Adds a class to the <body> when the slide is active.
data-preload (presence) Force preloading of slide content regardless of viewDistance.

Background Attributes

Attribute Values Description
data-background color/URL/gradient Shorthand for background (auto-detects type).
data-background-image URL Background image URL.
data-background-video URL Background video URL.
data-background-iframe URL Background iframe URL.
data-background-color CSS color Background solid color.
data-background-gradient CSS gradient Background gradient (e.g., linear-gradient(...)).
data-background-size CSS size Background image size (e.g., cover, contain).
data-background-position CSS position Background image position.
data-background-repeat CSS repeat Background image repeat mode.
data-background-opacity 0.0-1.0 Background opacity.
data-background-transition transition name Per-slide background transition.
data-background-video-loop (presence) Loop background video.
data-background-video-muted (presence) Mute background video.
data-background-interactive (presence) Allow interaction with background iframe.

Auto-Animate Attributes

Attribute Values Description
data-auto-animate (presence) Enable auto-animate for this slide.
data-auto-animate-id string Group auto-animate slides by ID (allows non-consecutive matching).
data-auto-animate-restart (presence) Start a new auto-animate sequence (no transition from previous).
data-auto-animate-easing CSS easing Per-slide easing override.
data-auto-animate-duration number (seconds) Per-slide duration override.
data-auto-animate-delay number (seconds) Per-element delay.
data-auto-animate-unmatched fade, none Behavior for unmatched elements.
data-id string Explicit element matching ID for auto-animate.

Fragment Animations

Applied as CSS classes on elements with class="fragment":

Animation Class Effect
fade-out Fades element out
fade-up Slides up while fading in
fade-down Slides down while fading in
fade-left Slides left while fading in
fade-right Slides right while fading in
fade-in-then-out Fades in, then fades out on next step
fade-in-then-semi-out Fades in, then semi-transparent on next step
grow Scales up from smaller
shrink Scales down from larger
strike Applies strikethrough
highlight-red Highlights text red
highlight-blue Highlights text blue
highlight-green Highlights text green
highlight-current-red Highlights red only while current
highlight-current-blue Highlights blue only while current
highlight-current-green Highlights green only while current

Custom animation classes are also supported -- any string value works and is applied as a CSS class.

Tip

Fragment order is controlled by data-fragment-index. Multiple elements can share the same index to animate simultaneously. When sortFragmentsOnSync is true (default), fragments are automatically sorted by their index.

8.4 Error Messages

Error Source Cause
"Unable to find presentation root (<div class="reveal">)" js/index.ts:44 Reveal.initialize() called without a .reveal element in the DOM (or the specified root element).
"Please specify a valid media type to preview" js/controllers/overlay.js:189 showPreview() called with a URL whose MIME type cannot be determined as image, video, or iframe.

8.5 Test Infrastructure

Framework Scope Location
QUnit + Puppeteer Core library integration tests test/ directory
Vitest + Testing Library + jsdom React wrapper unit tests react/ directory
TypeScript type tests Type declaration correctness test/types/plugin-imports.ts

Test HTML pages in test/ cover: auto-animate, dependencies, grid navigation, iframes, markdown, mathjax4, multiple instances, PDF, plugins, scroll, and state.

Run tests:

npm test            # Core: QUnit in headless Puppeteer
npm run react:test  # React wrapper: Vitest

9. Integration Points

9.1 React Wrapper (@revealjs/react v0.2.1)

The React wrapper lives in the react/ subdirectory and provides a declarative component API for building presentations in React.

Components

Deck -- The root component that wraps a reveal.js instance.

Prop Type Description
config RevealOptions reveal.js configuration object
plugins RevealPlugin[] Array of plugins to register
onReady (event) => void Fires when presentation is initialized
onSlideChange (event) => void Fires on slide navigation
onFragmentShown (event) => void Fires when a fragment becomes visible
onFragmentHidden (event) => void Fires when a fragment is hidden
deckRef React.Ref Ref to the underlying Reveal instance

Slide -- Maps to a <section> element with shorthand props for all data-* attributes.

Prop Type Maps To
background string data-background
autoAnimate boolean data-auto-animate
transition string data-transition
notes string data-notes
visibility string data-visibility
state string data-state

Stack -- Wraps vertical slides in a parent <section>.

Markdown -- Renders markdown content as slides.

Prop Type Description
children string Inline markdown content
src string External markdown file URL
separator string Horizontal slide separator
verticalSeparator string Vertical slide separator
notesSeparator string Notes separator
options object Passed to marked library

Fragment -- Wraps elements in fragment animations.

Prop Type Description
animation string Fragment animation class (e.g., 'fade-up')
index number Fragment ordering index
as string | Component Render as a different element type
asChild boolean Polymorphic rendering (passes props to child)

Code -- Renders syntax-highlighted code blocks.

Prop Type Description
language string highlight.js language identifier
lineNumbers string Line number / step-through spec
startFrom number Starting line number
trim boolean Enable whitespace trimming
noEscape boolean Disable HTML escaping

Hooks and Context

  • useReveal() -- Hook that returns the RevealApi instance from RevealContext. Must be called within a Deck component tree.
  • RevealContext -- React context providing the RevealApi instance.

Note

GitHub issue #3883 documents that React Markdown fragment directives are broken with Vite 8. Verify fragment behavior when using the Markdown component with the current build toolchain.

9.2 PostMessage API

When postMessage: true, reveal.js accepts commands from parent/child windows:

// From parent window controlling an embedded presentation
iframe.contentWindow.postMessage(JSON.stringify({
  method: 'slide',
  args: [2, 0]  // Navigate to slide 2
}), '*');

When postMessageEvents: true, all reveal.js events are forwarded as postMessage to the parent window, enabling external monitoring and synchronization.

9.3 Multiplexing and Synchronization

State synchronization between presenter and audience can be built using:

  1. getState() / setState() -- serialize and restore complete presentation state
  2. postMessageEvents: true -- forward all events to a parent frame or relay server
  3. slidechanged event -- includes indexh, indexv for remote navigation commands

9.4 Embedding

Set embedded: true for presentations embedded within larger pages:

  • Prevents capturing global keyboard events
  • Adjusts sizing behavior to fit within a container rather than the viewport
  • Multiple instances can coexist with independent navigation

9.5 Known Issues and Compatibility

Active GitHub issues relevant to administrators and developers:

Issue Summary
#3888 Decktape PDF export error
#3883 React Markdown fragment directives broken with Vite 8
#3821 npm install error
#3895 v6 Dracula theme background color incorrect
#3839 Whitespace normalization corruption
#3894 v6 not available on CDN
#3749 Incorrect TypeScript typing for keyboard config
#3860 PDF generates very large files
#3884 Fade-out / fade-in-then-out causes blank slides
#3878 Vertical background offset incorrect
#3869 .background CSS not scoped to reveal.js (leaks to page)

Caution

Issue #3869 reports that .background CSS selectors in reveal.js themes are not scoped and can leak styles to the host page. When embedding reveal.js in a larger application, use CSS containment or shadow DOM to prevent style conflicts.

9.6 Troubleshooting

Presentation Root Not Found

Error: "Unable to find presentation root (<div class="reveal">)"

Cause: Reveal.initialize() runs before the .reveal div exists in the DOM, or the element is missing entirely.

Solution: Ensure the HTML contains <div class="reveal"><div class="slides">...</div></div> and that initialization runs after DOM ready (e.g., in a DOMContentLoaded handler or at the end of <body>).

Prevention: Always verify DOM structure before calling initialize().

Plugins Not Loading

Error: ready event never fires; presentation appears stuck.

Cause: A plugin's init() method returned a Promise that never resolves or threw an error.

Solution: Check browser console for plugin initialization errors. Test with plugins: [] to confirm the issue is plugin-related. Add each plugin back one at a time to identify the failing one.

Prevention: Always handle errors in async plugin init() methods. Test plugin initialization in isolation.

PDF Export Issues

Error: Blank pages, missing content, or excessively large file size in PDF export.

Cause: Fragment-based pagination (pdfSeparateFragments: true) generates a page per fragment step. Complex backgrounds and media increase file size.

Solution: Set pdfSeparateFragments: false to reduce page count. Use pdfMaxPagesPerSlide to cap pages per slide. Remove or simplify heavy backgrounds before export.

Prevention: Test PDF export early in presentation development. Use ?print-pdf in the URL to preview print layout.

npm Install Failures

Error: Various errors during npm install (see issue #3821).

Cause: Node.js version below the required minimum (20.19.0) or platform-specific dependency issues.

Solution: Verify Node.js version with node --version. Ensure it meets the >= 20.19.0 requirement in package.json engines.

Prevention: Use nvm or fnm to manage Node.js versions and pin to a compatible version.