199 lines
5.9 KiB
Markdown
199 lines
5.9 KiB
Markdown
<p align="center">
|
|
<a href="https://revealjs.com">
|
|
<img src="https://hakim-static.s3.amazonaws.com/reveal-js/logo/v1/reveal-black-text-sticker.png" alt="reveal.js" width="500">
|
|
</a>
|
|
</p>
|
|
|
|
# @revealjs/react
|
|
|
|
`@revealjs/react` is a thin React wrapper around the [Reveal.js](https://revealjs.com) presentation framework. Describe your slides as React components and let the wrapper handle the rest.
|
|
|
|
## Installation
|
|
|
|
Install the package along with its peer dependencies:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```tsx
|
|
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, and `Stack` groups slides into a vertical column:
|
|
|
|
```tsx
|
|
import { Deck, Slide, Stack, 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>
|
|
</Deck>
|
|
);
|
|
}
|
|
```
|
|
|
|
## 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.
|
|
|
|
```tsx
|
|
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](https://revealjs.com/config/). `Slide` supports 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:
|
|
|
|
```tsx
|
|
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:
|
|
|
|
```tsx
|
|
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`:
|
|
|
|
```tsx
|
|
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.
|
|
- `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.
|
|
|
|
---
|
|
|
|
<div align="center">
|
|
MIT licensed | Copyright © 2011-2026 Hakim El Hattab, https://hakim.se
|
|
</div>
|