Exercise: Build a Reveal.js Presentation
Learning Goal
Build a real Quarto presentation: a single .qmd source that renders to a polished, web-native reveal.js slide deck you could give as a conference talk. Along the way you will add proper title-slide metadata, drop in a logo, build introductory and content slides, pull a figure straight from data, write speaker notes only you can see, and restyle the whole deck by changing a single line — first with Quarto’s built-in themes, then with a community theme.
This is the hands-on companion to the Creating Presentations page. The full reference for everything below is the Quarto reveal.js guide.
Two Ways to Do This Exercise
Pick whichever is more useful to you — the steps are the same either way:
- Path A — Bring your own. Turn a talk you already need to give (or a recent paper or poster) into a Quarto deck. You will get the most out of the exercise this way, because you end with slides you can actually present.
- Path B — Use our sample data. Build a short conference talk about ecological restoration from the dataset below — the same data behind the manuscript and dashboard exercises. Choose this if you would rather not wrangle your own material right now.
Wherever a step needs concrete code, we show it for the sample data. If you are on Path A, swap in your own slide titles, figure, and text.
The Sample Data (Path B)
restoration-sites.csv records quarterly monitoring of four restoration sites (A–D) from 2023 to 2025. Each row is one survey of one site:
site— the monitoring site (A–D)date— survey date (quarterly)vegetation_cover_pct— vegetation cover, in percentspecies_richness— number of species recordedsoil_moisture_pct— soil moisture, in percent
Download restoration-sites.csv Download restoration-scenarios.csv
(restoration-scenarios.csv holds vegetation cover under three management scenarios and is only needed for a stretch task.)
Step 1 — Create the Presentation File
A reveal.js presentation is just one .qmd file with format: revealjs. Make a folder to keep this exercise in (say my-talk/), and inside it create a file called talk.qmd with this minimal starter:
---
title: "Vegetation Recovery Across Four Restoration Sites"
format: revealjs
---
## First slide
Each level-2 heading (`##`) starts a new slide.Now preview it. Open talk.qmd in your editor and click Preview, or run this in a terminal sitting in the my-talk/ folder:
quarto preview talk.qmdA slide deck opens in your browser. Use the arrow keys to move through it; press F for fullscreen and Esc to leave. Leave the preview running — it refreshes every time you save.
You don’t have to start from scratch. In RStudio choose New File → Quarto Presentation → Reveal JS; in Positron or VS Code open the command palette and pick Quarto: Create Document. The result is the same kind of starter file.
Two heading levels shape the deck:
#(level 1) creates a section divider — a big title slide that breaks the talk into parts.##(level 2) creates a content slide.
Everything you write under a ## — text, bullets, a figure — lands on that slide.
Every R chunk in your real talk.qmd opens with ```{r} — with curly braces — so Quarto runs it. In the sketches on this page we write ```r without braces only so they display as text instead of executing. When you copy them into your file, add the braces back.
Step 3 — Add a Logo
A conference talk usually carries a logo — your institution’s, or the conference’s. Download the iEMSs 2026 logo (or use your own university’s):
Save it next to talk.qmd. Then tell reveal.js to use it. To add options to a format, you expand the single-line format: revealjs into a nested block:
format:
revealjs:
logo: iemss2026_logo.png
footer: "Vegetation recovery · iEMSs 2026"logo: pins your image to the bottom-right of every slide; footer: adds a line of text along the bottom. Render and you will see both.
Step 4 — Build Your Introductory Slides
A talk needs a way in. Add a section divider and an opening content slide before you reach any results. Two reveal.js features make these feel like slides rather than a wall of text:
- a list marked
{.incremental}reveals its bullets one click at a time; - a line containing just
. . .inserts a pause — the next content appears on the following click.
# Background {background-color="#2c3e50"}
## Why monitor restoration? {.incremental}
- Restoration projects *promise* recovery — but do sites actually recover?
- We surveyed four sites every quarter for two years
- That gives a simple, testable signal: change in vegetation cover
## Our question
. . .
How fast is vegetation cover recovering — and does the pace differ by site?The # Background line is a section slide (the {background-color=...} gives it a coloured backdrop); the two ## lines are content slides. Click through the preview to see the bullets and the pause reveal in turn.
Step 5 — Load Your Data in a Setup Chunk
Your results slide will draw a figure from the data, so load it once near the top. Make a data/ folder inside my-talk/ and copy restoration-sites.csv into it (use the download button above). Then add a setup chunk just below the front matter. include: false runs the code but keeps it — and any messages — off your slides:
```r
#| label: setup
#| include: false
library(readr)
library(dplyr)
library(ggplot2)
sites <- read_csv("data/restoration-sites.csv") |>
mutate(date = as.Date(date))
first <- sites |> filter(date == min(date)) # earliest survey per site
latest <- sites |> filter(date == max(date)) # most recent survey per site
```first and latest give the start and end of the monitoring period, which the next slide uses.
Step 6 — Add a Content Slide With a Figure and a Main Message
This is the heart of the talk. A good results slide makes one point — so put the message in the slide title, and let a figure carry the evidence. Use a two-column layout to set the chart beside a few takeaways:
## Cover is recovering at every site {.smaller}
:::: {.columns}
::: {.column width="60%"}
```r
#| echo: false
#| fig-width: 6
#| fig-height: 4.5
ggplot(sites, aes(date, vegetation_cover_pct, colour = site)) +
geom_line(linewidth = 1) +
geom_point() +
labs(x = NULL, y = "Vegetation cover (%)", colour = NULL) +
theme_minimal(base_size = 16)
```
:::
::: {.column width="40%"}
- Cover rose at **all four** sites
- Site D leads; Site C lags
- Mean cover is up **`r round(mean(latest$vegetation_cover_pct) - mean(first$vegetation_cover_pct))` points** since 2023
:::
::::
```Three things to notice:
echo: falseshows the plot but hides the code that made it — what an audience wants.- The
:::: {.columns}/::: {.column}blocks split the slide; adjust thewidthpercentages to taste. - That last bullet uses inline R,
`r ...`, so the headline number is computed from the data — exactly as in the manuscript exercise. Change the CSV and the slide updates itself.
The {.smaller} after the title shrinks the text on this one slide, which helps when a slide is busy.
Step 7 — Add Speaker Notes
Reveal.js has a presenter view that shows notes only you can see. Add a ::: {.notes} block to the bottom of your results slide:
## Cover is recovering at every site
<!-- your columns / figure / bullets from Step 6 -->
::: {.notes}
Remind the audience these are synthetic data. Point out Site C's slow start —
likely the driest site. Pause here for questions before moving on.
:::The notes never appear on the slide itself. To read them while presenting, press S in the browser to open speaker view — a separate window with your notes, a timer, and a preview of the next slide.
With the deck open in a browser: S opens speaker view, F goes fullscreen, O shows a slide overview grid, and E switches to a print layout for exporting to PDF.
Step 8 — Switch Between the Built-In Themes
Quarto ships with a set of reveal.js themes. Pick one with a theme: line under the format:
format:
revealjs:
theme: serif
logo: iemss2026_logo.png
footer: "Vegetation recovery · iEMSs 2026"Now try a few: swap serif for simple, moon, solarized, sky, league, night, or dracula and watch the preview restyle instantly. The content never changes — only the look.
Step 9 — Try the Custom “Clean” Theme
For a more distinctive title slide, install a community theme — Grant McDermott’s widely used quarto-revealjs-clean. From a terminal inside your my-talk/ folder:
quarto install extension grantmcdermott/quarto-revealjs-cleanThis adds an _extensions/ folder providing a new format, clean-revealjs. Switch to it by changing only the format line — the clean theme understands the same reveal.js options, so your logo and footer carry over:
format:
clean-revealjs:
logo: iemss2026_logo.png
footer: "Vegetation recovery · iEMSs 2026"Render again. Your title slide now uses the clean theme’s layout — and because the author block from Step 2 follows Quarto’s standard schema, your name, ORCID, and affiliation slot straight into it. That single-line swap, with everything else untouched, is the payoff of keeping content and styling separate.
clean-revealjs is a Quarto extension — a small bundle of CSS and templates that adds a new output format. It is the same mechanism behind the journal templates in the manuscript exercise. Browse more at the Quarto extensions listing.
Step 10 — Render to HTML
While writing you have been using quarto preview. For the finished file, render it:
quarto render talk.qmdThis produces talk.html — a complete, self-contained slide deck that opens in any modern browser, no internet or server required. That single HTML file is your presentation: open it to present, or send it to a colleague.
By default the HTML references a few supporting folders. To bundle everything into a single file you can email or drop on a USB stick, add one line under the format:
format:
revealjs:
embed-resources: trueStretch Tasks
If you finish early, try one of these:
- Compare management scenarios. Read
restoration-scenarios.csvin your setup chunk and add a results slide with a second figure coloured or faceted byscenario(Baseline / Moderate / Intensive) — the same data behind the scenarios dashboard. - Embed an interactive chart. Reuse a
plotlychart from the dashboard exercise on a slide — it stays live and hoverable in the browser, something PowerPoint can’t do. - Animate a transition. Put
{auto-animate=true}on two consecutive##slides and move or resize an element between them; reveal.js tweens it. Or settransition: slideunder the format for a global slide transition. - Add a chalkboard. Set
chalkboard: trueunder the format, then press B while presenting to draw on the slide live. - Export a PDF or PowerPoint. Press E then print-to-PDF for a handout, or add
pptx: defaultto theformat:block and render again for a PowerPoint version colleagues can edit.
Adapting Path A (Your Own Talk)
Converting a talk of your own follows exactly the same skeleton:
- Put your real title-slide details in the front matter, and your institution’s logo next to the file.
- Break your talk into
#section dividers and##content slides, one message per slide. - Re-create your key figure as a code chunk with
echo: false(or drop in an image with). - Move the script you would otherwise read aloud into
::: {.notes}blocks. - Try a built-in theme, then
clean-revealjs, and keep whichever fits your message.
Self-Check
- Does
quarto render talk.qmdproduce atalk.htmlyou can open in a browser? - Does the title slide show your name, affiliation, and the logo?
- Does at least one slide carry a figure drawn from the data, under a single clear message?
- Do your speaker notes show up in speaker view (press S) but never on the slides themselves?
- Can you switch from a built-in theme to
clean-revealjsby changing only theformat:line?