hakimel/reveal.js · critical · Error
Unable to find presentation root (<div class="reveal">).
Error message
Unable to find presentation root (<div class="reveal">).
What it means
Reveal.initialize (js/index.ts:30) bootstraps the singleton deck by querying document.querySelector('.reveal') and requires it to be an HTMLElement. If the selector returns null or a non-element node, initialize throws before constructing the Deck. This is the single hard precondition for bootstrapping reveal.js: the presentation root element must exist in the document at the moment initialize runs.
Source
Thrown at js/index.ts:44
* reveal.js API and ensures backwards compatibility.
* This API only allows for one Reveal instance per
* page, whereas the new API above lets you run many
* presentations on the same page.
*
* Reveal.initialize( { controls: false } ).then(() => {
* // reveal.js is ready
* });
*/
type RevealApiFunction = (deck: RevealApi) => any;
const enqueuedAPICalls: RevealApiFunction[] = [];
Reveal.initialize = (options?: RevealConfig) => {
const revealElement = document.querySelector('.reveal');
if (!(revealElement instanceof HTMLElement)) {
throw new Error('Unable to find presentation root (<div class="reveal">).');
}
// Create our singleton reveal.js instance
Object.assign(Reveal, new Deck(revealElement, options));
// Invoke any enqueued API calls
enqueuedAPICalls.map((method) => method(Reveal as RevealApi));
return Reveal.initialize();
};
/**
* The pre 4.0 API let you add event listener before
* initializing. We maintain the same behavior by
* queuing up premature API calls and invoking all
* of them when Reveal.initialize is called.
*/
(View on GitHub (pinned to a3b9406956)
Solutions
- Ensure the HTML contains <div class="reveal"> ... </div> and that initialize runs after it is parsed — wrap the call in DOMContentLoaded or place the script with defer at the end of <body>.
- Verify the element exists before initializing: const el = document.querySelector('.reveal'); if (el) Reveal.initialize(opts).
- Double-check the class spelling and that no build step strips class attributes from the root.
- If integrating under React/Vue/etc., defer Reveal.initialize to a post-mount effect where the root node is guaranteed present.
Example fix
// before (runs during module eval, DOM not ready)
import Reveal from 'reveal.js';
Reveal.initialize({ controls: true });
// after
import Reveal from 'reveal.js';
document.addEventListener('DOMContentLoaded', () => {
Reveal.initialize({ controls: true });
}); Defensive patterns
Strategy: validation
Validate before calling
function initializeWhenReady(options) {
const start = () => {
const root = document.querySelector('.reveal');
if (!(root instanceof HTMLElement)) {
console.error('Reveal: no <div class="reveal"> found in the document.');
return;
}
Reveal.initialize(options);
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start, { once: true });
} else {
start();
}
} Type guard
function hasRevealRoot(doc = document) {
return doc.querySelector('.reveal') instanceof HTMLElement;
} Try / catch
try {
Reveal.initialize(options);
} catch (e) {
if (/presentation root/.test(e.message)) {
document.addEventListener('DOMContentLoaded', () => Reveal.initialize(options), { once: true });
} else {
throw e;
}
} Prevention
- Always include <div class="reveal"> in the host HTML before initialize runs.
- Load your bootstrap script with defer or after DOMContentLoaded.
- When embedding in another framework, call initialize from a post-mount effect, not at module top level.
- Verify the class attribute is not stripped by SSR hydration or a CSS-in-JS transform.
When it happens
Trigger: Calling Reveal.initialize before the DOM is parsed (script in <head> without defer, or a module that runs during SSR where document has no .reveal); the root <div> missing the class attribute 'reveal'; the class mistyped (e.g. 'reveals', 'reveal.js'); a custom mount where the root was renamed; running initialize twice after the element was removed.
Common situations: Bundlers that execute the initialize call at import time instead of after DOMContentLoaded; embedding reveal.js into another framework's mount lifecycle that has not yet rendered the root; copy-paste setups that dropped the wrapper <div class="reveal">; ES module import order placing initialize ahead of the HTML.
AI-assisted analysis of hakimel/reveal.js@a3b9406956 (2026-08-12).
Data as JSON: /api/errors/a16be0e6fc98722b.
Report an issue: GitHub.