npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@revealjs/react

v0.2.0

Published

React wrapper for reveal.js

Readme

@revealjs/react

@revealjs/react is a thin React wrapper around the Reveal.js presentation framework. Describe your slides as React components and let the wrapper handle the rest.

Installation

Install the package along with its peer dependencies:

npm i @revealjs/react reveal.js react react-dom
# or
yarn add @revealjs/react reveal.js react react-dom

The package ships only the React bindings. You still need to import Reveal CSS, themes, and any plugins your deck uses.

Set up a deck

Render a Deck with one or more Slide children and import the core Reveal styles:

import { Deck, Slide } from '@revealjs/react';
import 'reveal.js/reveal.css';
import 'reveal.js/theme/black.css';

export function Presentation() {
  return (
    <Deck>
      <Slide>
        <h1>Hello</h1>
        <p>My first Reveal deck in React.</p>
      </Slide>

      <Slide background="#111827">
        <h2>Second slide</h2>
      </Slide>
    </Deck>
  );
}

Components

Alongside Deck and Slide, the package ships a few components for common slide patterns. Fragment reveals content one step at a time, Code renders a syntax-highlighted block via the highlight plugin, Stack groups slides into a vertical column, and Markdown renders Reveal-compatible markdown slides without registering the Reveal markdown plugin:

import { Deck, Slide, Stack, Markdown, Fragment, Code } from '@revealjs/react';
import RevealHighlight from 'reveal.js/plugin/highlight';
import 'reveal.js/plugin/highlight/monokai.css';

export function Presentation() {
  return (
    <Deck plugins={[RevealHighlight]}>
      <Slide>
        <h2>Step by step</h2>
        <Fragment animation="fade-up" as="p">First point</Fragment>
        <Fragment animation="fade-up" asChild>
          <div>Second point</div>
        </Fragment>
        <Code language="javascript" lineNumbers>
          {`console.log('Hello, world!');`}
        </Code>
      </Slide>

      <Stack>
        <Slide>Vertical 1</Slide>
        <Slide>Vertical 2</Slide>
      </Stack>

      <Markdown
        separator="^\n---\n$"
        verticalSeparator="^\n--\n$"
        options={{ smartypants: true, animateLists: true }}
      >
        {`
## Markdown 1.1
- First item <!-- .element: class="fragment" -->
- Second item <!-- .element: class="fragment" -->

--

## Markdown 1.2

Notes:
These become speaker notes.

---

<!-- .slide: data-background="#111827" -->
## Markdown 2
        `}
      </Markdown>
    </Deck>
  );
}

Markdown accepts string children, a markdown prop, or src for external markdown. Use the first-class separator, verticalSeparator, notesSeparator, elementAttributesSeparator, and slideAttributesSeparator props to mirror Reveal's markdown options, and pass any other markdown/Marked settings through options.

Configure Reveal

Pass any Reveal configuration through the config prop on Deck. Plugins are registered separately via plugins and are applied once at initialization time, matching Reveal's plugin lifecycle.

import { Deck, Slide } from '@revealjs/react';
import 'reveal.js/reveal.css';
import 'reveal.js/theme/black.css';
import 'reveal.js/plugin/highlight/monokai.css';
import RevealHighlight from 'reveal.js/plugin/highlight';

export function Presentation() {
  return (
    <Deck
      config={{
        width: 1280,
        height: 720,
        hash: true,
        controls: true,
        progress: true,
        transition: 'slide',
      }}
      plugins={[RevealHighlight]}
    >
      <Slide>Configured deck</Slide>
    </Deck>
  );
}

config maps directly to Reveal's configuration object. Slide and Markdown both support convenient Reveal slide props such as background, backgroundImage, backgroundColor, visibility, autoAnimate, transition, transitionSpeed, autoSlide, notes, backgroundInteractive, and preload, while still passing through raw data-* attributes to the rendered <section> element.

Subscribe to events

Use event props on Deck to respond to Reveal lifecycle and navigation events:

import { Deck, Slide } from '@revealjs/react';

export function Presentation() {
  return (
    <Deck
      onReady={(deck) => {
        console.log('Reveal ready', deck);
      }}
      onSync={() => {
        console.log('Deck synced');
      }}
      onSlideChange={(event) => {
        console.log('Slide changed', event.indexh, event.indexv);
      }}
      onFragmentShown={(event) => {
        console.log('Fragment shown', event.fragment);
      }}
    >
      <Slide>Intro</Slide>
      <Slide>Next</Slide>
    </Deck>
  );
}

Access the Reveal API

Use useReveal() inside the deck tree to call the Reveal API from your own components:

import { Deck, Slide, useReveal } from '@revealjs/react';

function NextButton() {
  const deck = useReveal();

  return <button onClick={() => deck?.next()}>Next slide</button>;
}

export function Presentation() {
  return (
    <Deck>
      <Slide>
        <h2>Controlled from React</h2>
        <NextButton />
      </Slide>
    </Deck>
  );
}

To access the Reveal instance outside of the component tree, pass a deckRef to Deck:

import { useRef } from 'react';
import { Deck, Slide } from '@revealjs/react';
import type { RevealApi } from 'reveal.js';

export function Presentation() {
  const deckRef = useRef<RevealApi | null>(null);

  return (
    <Deck deckRef={deckRef}>
      <Slide>Hello</Slide>
    </Deck>
  );
}

How it works

  • Deck creates one Reveal instance on mount and destroys it on unmount. Initialization is asynchronous — onReady fires once reveal.initialize() resolves, after which the instance is also accessible via useReveal() and deckRef.
  • Deck calls reveal.sync() when the rendered slide structure changes, such as slides being added, removed, reordered, or regrouped into stacks.
  • Slide handles slide-level data-* attribute updates locally with reveal.syncSlide(), so ordinary React content updates inside a slide do not trigger a full deck sync.
  • Markdown uses marked plus the same separator and comment-attribute conventions as Reveal's core markdown plugin, including .slide: and .element: comment syntax.
  • config is shallow-compared on each render so that reveal.configure() is only called when a value actually changes.
  • plugins are initialization-only, matching Reveal's plugin lifecycle. The prop is captured once on first mount and ignored on subsequent renders.
  • Event props are wired with deck.on() after initialization and cleaned up with deck.off(). Changing a callback between renders swaps the listener automatically.