Skip to content

Repository files navigation

React + Reveal.js Presentation Framework

Overview

A React-based presentation framework that combines the component model of React with the presentation features of reveal.js. Designed with Quarto-compatible theming and a path toward text-forward authoring in Markdown and Org-mode.

Key Features

  • Hybrid Architecture: React renders content, reveal.js handles navigation
  • Quarto-Compatible: SCSS variables and classes match Quarto conventions
  • Positioning System: Components accept position props (top, left, x, y)
  • Type-Safe: Full TypeScript support with comprehensive type definitions

Quick Start

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

Creating Presentations from QMD

This framework supports authoring presentations in Quarto Markdown (QMD), which are then compiled into standalone React+Reveal.js HTML files.

File Structure

Create a .qmd file in the examples/ directory (or anywhere):

---
title: My Presentation
author: Your Name
---

## First Slide

Content goes here.

## Second Slide

More content.

Building

Run the build script to compile your QMD file:

# Build to default output (dist/[filename]/)
npm run build:presentation -- examples/mypres.qmd

# Build to custom output location
npm run build:presentation -- examples/mypres.qmd -o dist/custom-name

The output is a folder containing index.html and bundled assets. Open it in a browser or deploy to any static host.

QMD Syntax Reference

Slides

Level-2 headings (##) create new slides:

## Slide Title

Slide content here.

## Another Slide {.center}

Centered slide (use ~{.center}~ attribute).

Two-Column Layout

Use fenced divs with .columns and .column:

## Two Columns

:::: {.columns}
::: {.column width="50%"}
Left column content.
:::

::: {.column width="50%"}
Right column content.
:::
::::

Fragments (Incremental Reveals)

Wrap content in {.fragment} divs or apply to inline spans:

::: {.fragment}
This appears on click.
:::

::: {.fragment .fade-up}
This fades up on the next click.
:::

Fragment styles: fade-in, fade-up, fade-down, fade-left, fade-right, grow, shrink, highlight-red, highlight-green, highlight-blue

Callouts

Use Quarto-style callout syntax:

::: {.callout-note}
This is a note callout.
:::

::: {.callout-tip title="Pro Tip"}
Callouts can have custom titles.
:::

::: {.callout-warning}
Warning message here.
:::

::: {.callout-caution}
Critical caution!
:::

Absolute Positioning

Position elements anywhere on the slide canvas:

::: {.absolute top="10%" left="5%"}
Positioned at top-left
:::

::: {.absolute bottom="10%" right="5%"}
Positioned at bottom-right
:::

Code Blocks

Standard fenced code blocks with syntax highlighting:

```typescript
const greeting = "Hello, World!";
console.log(greeting);
```

Styled Spans (Badges, Custom Classes)

Use Pandoc bracketed spans for inline styling:

[Badge Text]{.badge}

[Green Badge]{.badge style="background: #238636;"}

[Muted text]{.text-muted}

Slide Backgrounds

Add background attributes to slide headings:

## Dark Slide {background-color="#1a1a2e"}

Content on dark background.

## Image Background {background-image="photo.jpg"}

Content over image.

Complete Example

---
title: Sample Presentation
author: Jane Doe
---

## Welcome {.center}

[My Company]{.badge style="background: #2a76dd;"}

A brief overview of our work.

## Key Features

:::: {.columns}
::: {.column width="50%"}
::: {.callout-note title="Feature 1"}
Description of first feature.
:::
:::

::: {.column width="50%"}
::: {.callout-tip title="Feature 2"}
Description of second feature.
:::
:::
::::

## Roadmap

::: {.fragment}
Q1: Planning phase
:::

::: {.fragment}
Q2: Development
:::

::: {.fragment}
Q3: Launch
:::

## Questions? {.center background-color="#1a1a2e"}

[Contact us]{.badge} at hello@example.com

Build with:

npm run build:presentation -- examples/sample.qmd -o dist/sample

Component Reference

Core Components

Deck

Root presentation container. Initializes reveal.js and provides context.

<Deck
  config={{
    hash: true,
    transition: 'slide',
    controls: true,
  }}
>
  {/* Slides go here */}
</Deck>

Slide

Individual slide. Maps to a reveal.js <section>.

<Slide
  background={{ color: '#1a1a2e' }}
  center
  notes="Speaker notes here"
>
  <Heading level={1}>Title</Heading>
</Slide>
PropTypeDescription
backgroundstring or objectBackground color/image/video
centerbooleanVertically center content
transitionTransitionTypeSlide transition style
notesstringSpeaker notes
autoAnimate~| ~booleanEnable auto-animate

Layout Components

Columns / Column

Multi-column layout using flexbox.

<Columns gap="2rem" vcentered>
  <Column width="half">Left content</Column>
  <Column width="half">Right content</Column>
</Columns>

Width presets: half, third, two-thirds, quarter, three-quarters

Absolute

Position elements anywhere on the slide canvas.

{/* Using top/left */}
<Absolute top="10%" left="20%">
  <Text>Positioned</Text>
</Absolute>

{/* Using x/y shorthand */}
<Absolute x={100} y={200} width={300}>
  <Image src="photo.jpg" />
</Absolute>

{/* Centered */}
<Absolute x="50%" y="50%" style={{ transform: 'translate(-50%, -50%)' }}>
  <Heading level={1}>Centered</Heading>
</Absolute>

Stack

Overlay content for sequential reveals.

<Stack>
  <Fragment><Text>First</Text></Fragment>
  <Fragment><Text>Second</Text></Fragment>
  <Fragment><Text>Third</Text></Fragment>
</Stack>

Fragment

Incremental content reveals.

<Fragment style="fade-up">Appears on click</Fragment>
<Fragment style="highlight-blue" index={0}>Same time as first</Fragment>

Fragment styles: fade-in, fade-up, fade-down, grow, shrink, highlight-red, highlight-green, highlight-blue, etc.

Content Components

Heading

Typography with Quarto-compatible sizing.

<Heading level={1}>Main Title</Heading>
<Heading level={2} className="subtitle">Subtitle</Heading>

Text

Paragraphs with size, alignment, and styling props.

<Text size="lg" align="center">Large centered text</Text>
<Text muted>Secondary information</Text>
<Text weight="bold" primary>Emphasized text</Text>

Code

Syntax-highlighted code blocks.

<Code language="typescript" lineNumbers caption="Example">
{`const x = 42;
console.log(x);`}
</Code>

Callout

Quarto-style callout boxes.

<Callout type="note">Informational note</Callout>
<Callout type="tip" title="Pro Tip">Helpful advice</Callout>
<Callout type="warning">Be careful!</Callout>
<Callout type="caution">Critical warning</Callout>

Theming

SCSS Variables

Customize the theme by overriding Quarto-compatible SCSS variables:

// Typography
$presentation-font-size-root: 40px;
$presentation-heading-font-weight: 600;
$font-family-sans-serif: system-ui, sans-serif;

// Colors
$body-bg: #fff;
$body-color: #222;
$primary: #2a76dd;
$link-color: #2a76dd;

// Callouts
$callout-color-note: #0969da;
$callout-color-tip: #238636;
$callout-color-warning: #9a6700;
$callout-color-caution: #cf222e;

// Code
$code-block-bg: #f7f7f7;
$code-block-font-size: 0.55em;

CSS Classes

Layout and utility classes available:

  • .columns, .column, .is-half, .is-third
  • .absolute - for positioned elements
  • .r-stack - stacked overlays
  • .text-sm, .text-lg, .text-xl - size utilities
  • .text-muted, .text-primary - color utilities
  • .font-bold, .font-semibold - weight utilities

React Hooks

useReveal

Access the reveal.js API instance.

function NavigationButtons() {
  const reveal = useReveal()
  return (
    <>
      <button onClick={() => reveal?.prev()}>Previous</button>
      <button onClick={() => reveal?.next()}>Next</button>
    </>
  )
}

useSlideState

Get current presentation state.

function SlideIndicator() {
  const state = useSlideState()
  return <span>Slide {state.indexh + 1}</span>
}

useSlideEvent

Subscribe to reveal.js events.

useSlideEvent('slidechanged', (event) => {
  console.log('Now on slide', event.indexh)
})

Creating Presentations from Org-mode

Org-mode files (.org) are also supported with similar capabilities.

Building

npm run build:presentation -- examples/mypres.org -o dist/mypres

Org Syntax Reference

Slides

Level-1 headings (*) create slides:

* First Slide

Content here.

* Second Slide
:PROPERTIES:
:CENTER: t
:END:

Centered slide.

Two-Column Layout

Use #+BEGIN_COLUMNS blocks:

#+BEGIN_COLUMNS
#+BEGIN_COLUMN 50%
Left column content.
#+END_COLUMN

#+BEGIN_COLUMN 50%
Right column content.
#+END_COLUMN
#+END_COLUMNS

Fragments

Use #+ATTR_REVEAL: :frag or wrap in blocks:

#+BEGIN_FRAGMENT
This appears on click.
#+END_FRAGMENT

#+BEGIN_FRAGMENT fade-up
This fades up.
#+END_FRAGMENT

Callouts

Use #+BEGIN_CALLOUT blocks:

#+BEGIN_CALLOUT note "Important Note"
This is a note callout with title.
#+END_CALLOUT

#+BEGIN_CALLOUT tip
A helpful tip.
#+END_CALLOUT

Absolute Positioning

Use #+BEGIN_ABSOLUTE blocks:

#+BEGIN_ABSOLUTE top=10% left=5%
Positioned content.
#+END_ABSOLUTE

Styled Spans (Macros)

Use @@class:text@@ syntax for inline styling:

@@badge:Badge Text@@

@@text-muted:Muted text@@

Code Blocks

Standard Org source blocks:

#+BEGIN_SRC typescript
const x = 42;
console.log(x);
#+END_SRC

Complete Org Example

#+TITLE: Sample Presentation

* Welcome
:PROPERTIES:
:CENTER: t
:END:

@@badge:My Company@@

A brief overview.

* Key Features

#+BEGIN_COLUMNS
#+BEGIN_COLUMN 50%
#+BEGIN_CALLOUT note "Feature 1"
First feature description.
#+END_CALLOUT
#+END_COLUMN

#+BEGIN_COLUMN 50%
#+BEGIN_CALLOUT tip "Feature 2"
Second feature description.
#+END_CALLOUT
#+END_COLUMN
#+END_COLUMNS

* Questions?
:PROPERTIES:
:CENTER: t
:BACKGROUND_COLOR: #1a1a2e
:END:

Contact us at hello@example.com

Future Work

Native Emacs Exporter (Planned)

A custom ox-react.el backend for direct export from Emacs without the intermediate parsing step.

Project Structure

src/
├── components/           # React components
│   ├── Deck.tsx         # Root component
│   ├── Slide.tsx        # Slide container
│   ├── Heading.tsx      # Typography
│   ├── Text.tsx         # Text content
│   ├── Absolute.tsx     # Positioning
│   ├── Columns.tsx      # Layout
│   ├── Fragment.tsx     # Reveals
│   ├── Code.tsx         # Code blocks
│   └── Callout.tsx      # Callout boxes
├── hooks/               # React hooks
├── parser/              # Source file parsers
│   ├── qmd/             # QMD (Quarto Markdown) parser
│   ├── org/             # Org-mode parser
│   └── renderer.tsx     # AST to React renderer
├── styles/              # SCSS theming
├── types/               # TypeScript types
└── demo/                # Demo presentation
examples/
├── demo.qmd             # QMD demo presentation
└── demo.org             # Org-mode demo presentation
scripts/
└── build-presentation.ts # Build script for presentations

License

MIT

About

Experimentla project to build react-based reveal presentations from qmd and org files

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages