Yongfu's Blog

Tips to Reduce the Complexity of Slide Making with Xaringan

Although I’m a strong believer in R Markdown, I’m not so sure about it in the realm of slide making. After using GUI slide making tools such as Powerpoint or Google Slides for years, it is not easy to get used to making slides with markdown, since it requires additional processing in the brain – the conversion between images in the brain and the markup language to create them on the slides. xaringan::inf_mr() greatly reduces this burden on the brain, but one serious drawback still persists. When making slides with Markdown, the source document often gets very long. I frequently found myself lost in the source document (after scrolling up and down), not knowing which part of the slide is it that I’m looking at1. To be fair, there are great things about making slides with markdown, for example, it’s easier to manage and reuse images through URLs, and markdown is convenient for formatting code (automatic syntax highlighting).

I have been making a lot of slides with Xaringan lately. After spending hours on Xaringan, I began to have more faith in making slides with markdown because I figured out some tips to reduce the pain caused by markup langauges. The idea is simple – reduce the length and complexity of the source R Markdown document. knitr is my friend here.

Use Several Source Documents

bookdown uses several Rmd files to generate a book. The same idea can be used in Xaringan, and here are some advantages I can think of:

  • By splitting the source document into several meaningful sub-documents, you can locate particular parts of your slide faster (the so-called “chunking”).

  • Your slides can be easily reused, since you can copy a part of your slides by choosing the relevent Rmd file(s). (Not copy-and-pasting text from the parts you want in one lengthy Rmd file)

Child Document

To use several source Rmd documents to generate a single Xaringan (or any R Markdown) output, use knitr chunk option child to include other Rmd files in a Rmd document. For example, I would create one index.Rmd and several Rmd files with meaningful names (e.g., opening.Rmd, intro-github.Rmd, contact.Rmd, etc.):

 2├── index.Rmd
 3├── opening.Rmd
 4├── intro-github.Rmd
 5├── contact.Rmd
 6├── html-table.txt
 7├── img/
 8└── addons/
 9    ├── custom.css
10    └── macros.js

The chunk option child is then used in index.Rmd to include other *.Rmd:

 2```{r setup, include=FALSE}
 3knitr::opts_chunk$set(echo = FALSE)
 4options(knitr.duplicate.label = 'allow')
 7```{r child='opening.Rmd'}
10```{r child='contact.Rmd'}

Complex Markups in Independent Files

Sometimes we may want to put cool things in the slides that can only be created from HTML syntax, for example, the table below (generated from TablesGenerator.com):


This table looks simple, but it is generated by a 2728-character-long HTML code, which greatly increases the length and complexity of the source document. To make the source document cleaner, you can put code of these kinds in separate text files and include them into the R Markdown source document by knitr::asis_output(readLines('html-table.txt'))2 and R Markdown inline code r :

1A table generated from
4`r knitr::asis_output(readLines('html-table.txt'))`

remark.js Built-in Functionalities

remark.js actually provides useful functionalities to help reduce the complexity of the slides. READ THE DOCs, and it might save you a great deal of time. Xaringan and remark.js both provide good wiki pages, and I regret I read them too late – after I spent a lot of time copy-and-pasting and made my Rmd source document uglier.

Below are some notes extract from Xaringan & remark.js Wiki pages. They serve as quick references (for myself) and aren’t meant to be detailed. Again, READ THE DOCs!


Xaringan Configuration (remark has a more thorough documentation) is set in YAML frontmatter:

 2  xaringan::moon_reader:
 3    nature:
 4      ratio: "16:10"
 5      beforeInit: ["addons/macros.js", "https://platform.twitter.com/widgets.js"]
 6      highlightLines: true
 7      highlightSpans: false
 8      navigation:
 9        scroll: false
10    css: [default, default-fonts, addons/custom.css]
11    yolo: false
12    seal: true

remark Special Syntax

  • name: Adding ID to a slide

    name: about
    ## About
    • reference with see [About](#about)
  • count

    count: false
    This slide will not be counted.
  • template

    name: template-slide
    Some content.
    template: template-slide
    Content appended to template-slide's content.
  • layout


  • Image with Absolute postition:

    Define macros in addons/macros.js:

    1remark.macros['abs'] = function(width="30%", left="85%", top="15%", cl="") {
    2var url = this;
    3return '<img src="' + url + '" style="position:absolute;left:' + left + ';top:' + top + ';width:' + width + '" class="' + cl + '" />';

    Use it in markdown:

    1![:abs width, left, top](url)
    3![:abs 30%, 50%, 0%](url)
    5<img src="url" style="position:absolute; width:30%; left:50%; top:0%;">

  1. This is the major drawback of markup languages compared to GUI authoring tools. Although markdown itself is designed to deal with this drawback (i.e. the too-complicated HTML syntax), the inherently complex structure of slideshows still complicates the source document of the slides writen in markdown. ↩︎

  2. Note that there is only one line in html-table.txt so readLines() returns a character vector of length 1. If there are multiple lines in the text file, one needs to use paste(readLines('html-table.txt'), collapse = '\n') to properly print out the text file. ↩︎