4.5 xaringan Presentation

It is a slide template based on an HTML5 presentation framework remark.js.

Basically xaringan injected R Markdown (minus Pandoc) into remark.js. The slides are rendered by remark.js in the web browser, and the Markdown source needed by remark.js is generated from R Markdown (knitr).

You write slides in R Markdown, and then use the xaringan package to render the slides.

Features:

  • Interactive like html notes, but in form of slides, making it equivalent to PowerPoint, which students are more used to.

  • Support the choice of Google fonts.

    Quote Xie, “The best fonts are always the fonts I have never used by myself.” I cannot agree more. 🤣

When you decide to use xaringan, read tutorials HERE.

To create a new xaringan presentation, you simply create a new R Markdown document and use the following YAML header:

---
title: "Presentation Ninja"
subtitle: "with xaringan"
author: "Yihui Xie"
date: "2016/12/12"
output:
  xaringan::moon_reader:
    css: ["xaringan-themer.css", "custom.css"]
    lib_dir: libs
    include:
      in_header: libs/mathjax.html
    nature:
      highlightStyle: github
      highlightLines: yes
      countIncrementalSlides: false
      ratio: '16:9'
---

One slide.

---

Another slide.

xaringan::moon_reader is the main R Markdown output format in the xaringan package.

See the R help page ?xaringan::moon_reader for all possible configurations.

Configurations:

  • lib_dir: The directory to save the dependencies (e.g. jquery, bootstrap, etc.) of the slides.

    This is an argument passed to rmarkdown::html_document. See the help page ?rmarkdown::html_document for additional configurations provided by html_document.

    • By default this will be the name of the document with _files appended to it.
    • Here I set it to be libs.
  • includes: Named list of additional content to include within the document (typically created using the includes function).

    • in_header: Vector of file paths to be included in the document header (inside the <head> tag). Note that paths should be in quotation marks.
    • before_body: Vector of file paths to be included immediately after the opening <body> tag.
    • after_body: Vector of file paths h to be included immediately before the closing </body> tag.

    Include multiple files by passing a vector of file paths.

    includes:
      in_header: ["libs/mathjax.html", "libs/in_header.html"]
      after_body: ["theme/example-numbering.html", "libs/after_body.html"]

    Alternatively, use YAML list indentation with - for each file:

    includes:
      in_header: 
        - libs/mathjax.html
        - libs/in_header.html
      after_body: 
        - theme/example-numbering.html
        - libs/after_body.html

    Each list item is treated as a separate file path.

    ref: https://stackoverflow.com/a/45261469

  • nature: (Nature transformation) A list of configurations to be passed to remark.create(), e.g. list(ratio = '16:9', navigation = list(click = TRUE)).

    See Wiki page of remark.js for all possible configurations.


4.5.1 Render Slides

There are two steps to render slides to pdf:

  1. Render Rmd to html with rmarkdown::render
  2. Print html to pdf with pagedown::chrome_print
rmarkdown::render('equity_valuation.Rmd')
pagedown::chrome_print('equity_valuation.html')

Two-in-one option:

✅ use renderthis package to render slides and print to pdf in one function.

renderthis::to_pdf('equity_valuation.Rmd')

This will call rmarkdown::render and then pagedown::chrome_print automatically. Will generate equity_valuation.html and equity_valuation.pdf accordingly based on your output formats.


Issue: Fonts are not embedded / applied in the pdf output.

Fix: Set pdf output font specifically.

@media print {
    body {
        font-family: 'Noto Sans', -apple-system, BlinkMacSystemFont, system-ui, Arial, sans-serif !important;
        font-weight: 400 !important;
    }
    strong, b {
        font-weight: 700 !important;
    }
    /* MathJax font for print */
    .mjx-chtml {
        font-family: 'Georgia Pro', 'Libertinus Serif', serif !important;
        font-weight: 700 !important;
        color: red !important; /* for testing purpose, whether selector is correct */
    }
}
  • Note that .mjx-chtml controls math typesetting. The tricky point is that MathJax CommonHTML math uses its own fonts for math rendering, and CSS font-family is NOT respected.

  • Color and font-weight may work, but font-family is limited by MathJax’s internal font stack. For true font control, you need to change MathJax’s configuration, which is not easily done in xaringan.

  • html output and pdf output may use different fonts.

    Issue: If keeping @import in CSS, I cannot get the font applied in pdf output.

    Fix: What I do, a compromise solution, is to

    • use system font for html output, and
    • specify local font for pdf output.

4.5.2 Remark Markdown Basics

Remark.js uses its own flavor of Markdown, which is different from Pandoc’s Markdown! It is limited but should be sufficient for most use cases.

Features that are provided in Pandoc but missing in remark.js’s Markdown:

  • fancy lists (ordered lists with letters, e.g., a., b., c., etc.)

4.5.2.1 Create a New Slide

  • Every new slide is created under three dashes (---).

  • Two dashes (--) create a new fragment (incremental reveal) within the same slide.

    • Blank lines before and after the two and three dashes are required.
    • No whitespace after the dashes.
  • The content of the slide can be arbitrary, e.g., it does not have to have a slide title, and if it does, the title can be of any level you prefer (###, or ###).


4.5.2.2 Slide Properties

  • A slide can have a few properties, including class and background-image, etc.

    Properties are written in the beginning of a slide, e.g.,

    ---
    
    class: center, inverse
    background-image: url("images/cool.png")
    
    # A new slide
    
    Content.
  • The class property assigns class names to the HTML tag of the slide, so that you can use CSS to style specific slides.

    This will apply class to the whole slide.

    class: center, middle
    
    # Slide with content centered in both dimensions

    will be rendered as:

    <div class="remark-slideshow">
      <div class="remark-slide">
        <div class="remark-slide-content center middle">
          <h1>Slide with content centered in both dimensions</h1>

    Built-in classes include: leftcenterrighttopmiddle and bottom, which may be used to align entire slides.

  • background-image: Sets a background image for the slide.

  • name: Assigns a unique name to a slide, allowing for direct linking or referencing within the presentation (e.g., slides.html#my-slide-name).


4.5.2.3 Add Attributes

Follow remark syntax to add attributes to elements.

Inline Attributes:

.class[text to be styled]

will be rendered as:

<span class="class">text to be styled</span>

Nested inline attributes:

.footnote[.red.bold[*] Important footnote]

will be rendered as:

<span class="footnote">
  <span class="red bold">*</span> Important footnote
</span>

Block Attributes:

If you wish to have <div> tags instead, separate your content on new lines.

.class[
# Slide Title
Content of the slide.
]

will be rendered as:

<div class="class">
  <h1>Slide Title</h1>
  <p>Content of the slide.</p>
</div>

Another example:

.footnote[.red.bold[*]
Important footnote]

.footnote[
.red.bold[
*]Important footnote]

will be rendered as:

<div class="footnote">
  <span class="red bold">*</span>
  Important footnote
</div>

<div class="footnote">
  <div class="red bold">*</div>
  Important footnote
</div>

remark GitHub Wiki: Content Classes


4.5.3 Math Environments

Display math enclosed in double dollar signs ($$...$$), but note that

  • the dollar signs ($$) should not appear on separate lines
  • No space between $$ and the math content

This won't work:
$$
E = mc^2
$$

This will work:
$$E = mc^2$$

In html tags, math should be enclosed in \( ... \) for inline math and \[ ... \] for display math.

  • If using $...$, there are backticks surrounding the math after rendering…

4.5.3.1 Color equations

  1. In mathjax configuration file, define color macros, e.g., in libs/mathjax.html:

    <!-- MathJax V2 Configuration -->
    <script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      TeX: {
        extensions: ["color.js"], // load the color extension, support color names, RGB, and grey-scale color spaces
        equationNumbers: { autoNumber: "AMS" }, // use ams rules to number equations
        Macros: {
          // define colors
          red: ["{\\color[RGB]{185,64,71}{#1}}", 1],
        }
      }
    });
    </script>
  2. In your slide, you can use the macros, e.g., \red{...}, \blue{...}, etc.

    $$\red{Y_t} \equiv I_tI_{t-1} + (1-I_t)(1-I_{t-1})$$

4.5.4 Bullet list

Third level lists need an extra tab. ↩︎

Q: I think you need four spaces (or a true tab instead of two spaces) to indicate a new level. The syntax of remark.js’s Markdown is different with Pandoc’s Markdown. This works fine:

# Hello World

- Here are some bullet points using markdown syntax
    - Here's the next level
        - And this should be a lower level, but it isn't
            - Whereas this is:

- To summarise:
    - To get third level bullets:
        - You have to use an extra tab on the third level.

1. No tabs
    1. One tab
        1. Two tabs
            1. Three tabs

4.5.4.1 Ordered list with letters

Issue: xaringan does not recognize letters as list markers for ordered lists by default.

Explain: xaringan uses remark.js to render slides, which uses its own markdown parser that does not support letters as list markers for ordered lists. You cannot “load” fancy_lists directly in xaringan even if you add pandoc_args: ["-f", "markdown+fancy_lists"] to your YAML. It won’t have an effect — because xaringan::moon_reader doesn’t use Pandoc’s list rendering and therefore will ignore the args. The Markdown is passed to remark.js, which uses its own internal syntax rules.

Fix: Use CSS to customize the list style or use html tags directly.

  1. Define a custom class in CSS, e.g., in custom.css:

    /* Lettered lists */
    .remark-slide-content .alpha-list ol {
        list-style-type: lower-alpha; /* or upper-alpha for uppercase letters */
    }

    Then you can apply this class to a list:

    .alpha-list[
    1. First item
    2. Second item
       1. Subitem
       2. Subitem
    3. Third item
    ]

    will be rendered as:

    a. First item
    b. Second item
       i. Subitem
       ii. Subitem
    c. Third item
  2. Use html tags directly:

    <ol type="a">
      <li>First item</li>
      <li>Second item
        <ol type="i">
          <li>Subitem</li>
          <li>Subitem</li>
        </ol>
      </li>
      <li>Third item</li>
    </ol>

    will generate the same output as above.


4.5.5 Tables

Q: How to make the tables more compact, e.g, reduce the row height?

A: You can use CSS to adjust the table styles. For example, add the following CSS rules to your custom CSS file (e.g., custom.css):

/* Compact table styling */
.compact-table table {
    line-height: 1.2;
    font-size: 0.9em;
}

.compact-table th,
.compact-table td {
    /* vertical padding: 2px; */
    /* horizontal padding: 8px */
    padding: 2px 8px !important; 
}

Then, in your slide, wrap your markdown table with a div that has the compact-table class:

.compact-table[
| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Row 1    | Data     | More Data|
| Row 2    | Data     | More Data|
]

If your table is generated from R code, you can modify the HTML output to include the class:

```{r echo=FALSE, results='asis'}
tbl_html <- knitr::kable(df, format = "html") %>%
  as.character()
tbl_html <- sub("<table", '<table class="compact-table"', tbl_html)
cat(tbl_html)
```

Note that:

  • as.character() converts the HTML table to a character string so that you can manipulate it as text.
  • sub("<table", '<table class="compact-table"', tbl_html) searches for the first occurrence of <table in the HTML string; replaces it with <table class="compact-table". This adds the class .compact-table to the <table> tag, which allows you to style it using your CSS (like the .compact-table CSS you showed earlier).
  • cat(tbl_html) prints the modified HTML string to the slide. cat is required here because you want to output the HTML directly, not as a character string.

Q: I want to add more horizontal spacing in table cells, but keep narrow left spacing for the 1st column.

A: Add the following CSS rules to your custom CSS file (e.g., custom.css):

/* Add horizontal spacing in table cells, but keep narrow left spacing for the 1st column */
.fit-comp-table td,
.fit-comp-table th {
    padding: 4px 18px !important; /* increase horizontal padding */
}

.fit-comp-table th:first-child,
.fit-comp-table td:first-child {
    padding-left: 4px !important; /* tight left spacing for 1st column */
}

Then, in your slide, wrap your table with a div that has the fit-comp-table class:

```{r echo=FALSE, results='asis'}
fit_comp <- tibble(
  Metric = c("Residual Std. Error: CAPM", "Residual Std. Error: FF-3"),
  AAPL = c("0.092", "0.089"),
  SLAB = c("0.116", "0.107"),
  KO = c("0.046", "0.044")
)
tbl_html <- fit_comp %>%
  knitr::kable(format = "html", align = c("l", "c", "c", "c")) %>%
  as.character()
tbl_html <- sub("<table", '<table class="fit-comp-table"', tbl_html)
cat(tbl_html)
```

4.5.6 Images

Issue: Image resolution too low.

Fix: Add fig.retina=3 to chunk options for html output. Use dpi=300 for pdf output.


Issue: No figure numbering.

Explanation: xaringan uses remark.js to render slides, which does not support figure numbering. This is because referencing of figures across multiple slides is less common and potentially less effective for audience engagement. 😂


4.5.7 Presenter Notes

Q: Why using presenter notes?

A: A common mistake in presentations, especially for presenters without much experience, is to stuff a slide with too much content. The consequence is either a speaker, out of breath, reading the so many words out loud, or the audience starting to read the slides quietly by themselves without listening. Slides are not papers or books, so you should try to be brief in the visual content of slides but verbose in verbal narratives. If you have a lot to say about a slide, but cannot remember everything, you may consider using presenter notes.


Q: How to add presenter notes in xaringan?

A: In xaringan, presenter notes are written with ???.

Everything after ??? (on the same slide) will not appear on the slide, but will show up in presenter mode when you press p to toggle presenter view.

---

The holy passion of Friendship is of so sweet and steady
and loyal and enduring a nature that it will last through
a whole lifetime...

???
This is notes for presenter only.

Q: What is the behavior of presenter mode?

A: The presenter mode shows thumbnails of the current slide and the next slide on the left, presenter notes on the right (see Section 7.3.5), and also a timer on the top right.

The keys c and p can be very useful when you present with your own computer connected to a second screen (such as a projector).

On the second screen, you can show the normal slides, while cloning the slides to your own computer screen and using the presenter mode.

Only you can see the presenter mode, which means only you can see presenter notes and the time, and preview the next slide. You may press t to restart the timer at any time.

⚠️ One thing to check: if you mirror your display instead of extending it, then the audience will see exactly what you see (including notes). To avoid this, make sure you use extended display mode so only you get the presenter view.

The figure below shows the Displays settings on macOS for extended display mode.

  • Do not check the box “Mirror Displays”.
  • Instead, separate the two displays, so you can drag the window with the normal view of slides to the second screen.

Ref: R Markdown: The Definitive Guide, Section 7.3.5

4.5.8 CSS and themes

The format xaringan::moon_reader has a css option, to which you can pass a vector of CSS file paths, e.g.,

---
output:
  xaringan::moon_reader:
    css:["default", "extra.css"]
---
  • The file path should contain the extension .css. If a path does not contain a filename extension, it is assumed to be a built-in CSS file in the xaringan package.

  • Make sure to insert the relative path to the file if it is not placed in the same directory as your .Rmd file.

  • When you specify multiple CSS files, the one that comes later will take priority and override the previous ones if there are conflicting CSS rules.

  • To see all built-in CSS files, call xaringan:::list_css() in R.

    xaringan:::list_css() # print path of built-in CSS files
    names(xaringan:::list_css()) # print names only
  • When you only want to override a few CSS rules in the default theme, you do not have to copy the whole file default.css; instead, create a new (and hopefully smaller) CSS file that only provides new CSS rules.

  • Users have contributed a few themes to xaringan. For example, you can use the metropolis theme (https://github.com/pat-s/xaringan-metropolis):

Read R Markdown: The Definitive Guide, Section 7.5 for more details about CSS and themes.


4.5.9 Smart Punctuation

xaringan-smartify provides a javascript hack to turn ugly quotes and dashes (' " -- ---) into their pretty versions (‘ ’ “ ” – —) in xaringan HTML slides.

Follow instructions on xaringan-smartify GitHub Repo.


4.5.10 Working offline

Making the slides work offline can be tricky, since you may have other dependencies. For example, if you used Google web fonts in slides (the default theme uses Yanone KaffeesatzDroid Serif, and Source Code Pro), they will not work offline unless you download or install them locally.

To make slides work offline, you need to download a copy of remark.js in advance, because xaringan uses the online version by default.

Refer to R Markdown: The Definitive Guide, Section 7.6.4 for details.

4.5.11 Parser

  • Remark default parser (default in xaringan):

    • Very lightweight, fast ✅

    • Recognizes special syntaxes like .class[ text ]-- for incremental reveals, ??? for presenter notes

    • But doesn’t support fenced divs ::: or Pandoc extensions like footnotes, definition lists, etc.

  • Pandoc parser (when you set markdown: pandoc in yaml):

    • Full Pandoc Markdown support → you can use fenced divs, footnotes, definition lists, tables with alignment, math extensions, etc.

    • However, some remark-specific syntaxes may stop working or behave differently, especially:

      • .class[ text ] sometimes doesn’t parse as expected

      • Indentation rules for lists and code can be stricter

      • Incremental slides (--) still work, but spacing quirks can appear

      • Raw HTML might be handled slightly differently


4.5.12 xaringanExtra

The xaringanExtra package provides additional functionalities and themes for xaringan presentations.

Highlight features:

  • Add a search box to search through your slides with search

    ```{r xaringanExtra-search, echo=FALSE}
    # add search box
    xaringanExtra::use_search(show_icon = TRUE, position = "bottom-left")
    ```

    In your slides, press Control + F to start searching, or click on the search icon 🔍 if you set show_icon = TRUE.

    • Press Enter to jump to the next match.

      On Mac,

      • use ctrl + G to go to next match, and ctrl + shift + G to go to previous match.
      • use esc to exit search mode.
    • Defaults to case-insensitive. Can be changed with case_sensitive = TRUE.

  • Tile view

```{r xaringan-tile-view, echo=FALSE}
xaringanExtra::use_tile_view()
```

Tile view gives you a way to quickly jump between slides. Just press O (the letter O for Overview) at any point in your slideshow and the tile view appears.

Click on a slide to jump to the slide, or press O to exit tile view.

  • Add a progress bar at the bottom of your slides with progress bar

    Might not be necessary if you page numbers already.

```{r xaringanExtra-progressbar, echo=FALSE}
# add progress bar
xaringanExtra::use_progress_bar(color="red", location="top", height="0.25em")
```

GitHub repo


4.5.13 FAQ

Q: Error when using kableExtra in xaringan slides? See error message below:

Warning: A runtime exception has occurred while executing JavaScript Runtime exception message: ReferenceError: $ is not defined


Tutorials: