Skip to main content

Marp and Slidev alternative inside a React app

First, what this doesn't do. Marp and Slidev export decks to PDF and PPTX from the command line, and reveal.js prints to PDF from the browser. @react-markdown-kit/slides has no export command and can't write PPTX. If what you need at the end is a file to email, use one of those three.

What it does is turn Markdown your React app already renders into a deck, on the same page and through the same <Markdown> component. You don't need a second toolchain or a second copy of the content, and there's no separate static site to deploy next to your app.

npm install @react-markdown-kit/renderer @react-markdown-kit/slides
import Markdown, { defineMarkdownPreset } from '@react-markdown-kit/renderer'
import { slides } from '@react-markdown-kit/slides/present'
import '@react-markdown-kit/slides/styles.css'

const preset = defineMarkdownPreset({ extensions: [slides()] })

<div className="rmk-document">
<Markdown preset={preset}>{deck}</Markdown>
</div>

What each tool does​

MarpSlidevreveal.js@react-markdown-kit/slides
Runs asa CLI, a VS Code extension, a bundled HTML filea Vite dev server and a built single-page appa page you hosta component in a React tree you already have
Deck sourceMarkdown, --- breaks, directives in HTML commentsMarkdown, --- breaks, per-slide front matter, Vue componentsHTML sections, or Markdown through its pluginthe same Markdown file, --- breaks, ??? notes, -- fragments (DIALECT.md)
ExportHTML, PDF, PPTX, PNG (Marp CLI)PDF, PNG, PPTX (exporting)print to PDF (PDF export)browser print, one slide per page (styles.css); no PPTX
Present modepresenter view in the editor and the CLI previewpresenter mode with notes (UI)speaker view pluginpresent mode, presenter view, cross-window sync (present.dom.test.tsx)
Server renderinga build step writes the HTMLa build step writes the HTMLthe page ships the deckthe deck is built from the parsed tree, so a server component emits it (same suite)
Stylinga theme is a CSS file of Marp's classesUnoCSS and Vue componentsa theme is a CSS file of reveal's classesdata attributes and --rmk-slide-* properties, no class from the kit (extension.test.tsx)
Editingyour editor, with a previewyour editor, with hot reloadyour editorthe same file, plus a rich editor with four deck commands (editor-toolbar.test.tsx)

Each entry in the last column links to the test or file it comes from.

The deck, rendered by the kit​

The deck below isn't a screenshot. It was rendered when this page was built, by the same renderer that draws this paragraph. Click Present and use the arrow keys to move through it.

A three-slide deck, rendered in this page
Markdown
---
title: Release review
---

## Release review

One Markdown file. A document in the docs route, a deck in the talk route.

---

<!-- class: center, middle -->

## No export step

- The deck is a React component
- The notes ship in the DOM, hidden

???

Say that the source is the same file the docs page renders.

---

## Ship it

Questions?
Rendered

Release review

One Markdown file. A document in the docs route, a deck in the talk route.

No export step

  • The deck is a React component
  • The notes ship in the DOM, hidden

Ship it

Questions?

The static stack shows every slide at once. Present mode takes over the viewport, and Escape gets you back to this page.

Coming from a Marp deck​

MarpHere
--- between slidesthe same, at the root of the document
<!-- _class: lead --> on one slide<!-- class: center, middle -->, one directive per comment
<!-- theme: gaia -->a stylesheet of yours, set through --rmk-slide-* properties
notes in an HTML commenta paragraph that is exactly ???, then the notes
fragments from the list marker, * for bullets and ) for ordered lists (fragmented list)a paragraph that is exactly -- between the blocks to reveal
background images through ![bg](…)<!-- background: … -->, run through the renderer's URL policy
front matter for the whole deckfront matter for the whole deck: title, aspect, class, background

The dialect is written out in DIALECT.md and on the slides page. If the plugin doesn't accept a construct, it reports a diagnostic with the source range instead of silently dropping it.

Stay with Marp or Slidev when​

  • You need a file at the end. A PDF for a conference upload, or a PPTX for a colleague who edits in PowerPoint, is what those tools are for, and this plugin doesn't do it.
  • The deck stands on its own with no app around it. A CLI is probably less work.
  • You want Vue components, UnoCSS or Monaco inside slides, which is how Slidev is built.
  • You want a theme you can install. Marp and reveal.js both have theme ecosystems. This only has CSS custom properties, and there are no themes to install.

Use this plugin when​

  • The content already lives in your React app and is already rendered as Markdown. In that case a deck is one more preset rather than a second pipeline.
  • The deck has to sit behind your auth, your routing or your data. It's a component, so you control the page around it.
  • The same file needs to stay readable as a document. A deck is CommonMark or GFM with a few rules on top, so GitHub and a diff still show it as prose.
  • The deck has to render on the server. A root handler builds it from the parsed tree, so a server component emits the full markup.
  • The people editing it don't write Markdown by hand. The editor entry adds New slide, Speaker notes, Pause and Background as toolbar buttons, tested in editor-toolbar.test.tsx.

What a CLI cannot give you​

  • One source. The deck and the document are the same file, and if you load and save a deck without editing it, it's written back byte for byte (round-trip.test.ts).
  • The renderer's security policy. A javascript: background loses its src the same as any other URL in the document (extension.test.tsx), under the same security model as the rest of your content.
  • Markup you can style. Apart from slide-<name> ids, the deck doesn't emit any class, inline style or id, so your stylesheet doesn't need anything from the kit.
  • No runtime for the static deck. The root entry only loads the parser. React comes in with the present entry, and Lexical only with the editor entry (packaging.test.ts).

Questions​

Is there a Marp alternative that runs inside a React app?
This plugin is one option. It adds slide rules to the Markdown renderer you already use, so a deck is a component in your own routes instead of a separate site or build step.
Can I export a deck to PDF or PPTX?
There is no export command. The shipped stylesheet gives each slide its own page under @media print, so you can print a deck to PDF from the browser. If you need PPTX, use Marp or Slidev.
Does an existing Marp deck render unchanged?
The slide breaks, prose and code fences should render unchanged. Marp directives, themes and its image sizing syntax won't; the mapping table on this page shows what to use for each one.
Do I have to move my content out of my app?
No. The deck is the same Markdown file the renderer already reads, so a document and a deck are one source and one pipeline.

Next​

The slides demo · The demo without its chrome, for an iframe · Markdown presentations in React · @react-markdown-kit/slides on npm · The renderer · Security model