Revealjs Plugins

Quarto v1.2 Required

If you are using or developing extensions you should update to Quarto v1.2, which includes significant improvements to the extension API. Many extensions are also likely to require Quarto v1.2.

Overview

Revealjs plugins enable you to extend the capabilities of HTML presentations created with Revealjs. The Reveal Plugin API is very rich, and many of the built-in capabilities of Quarto Revealjs presentations are implemented as plugins, including Menu, Chalkboard, and PDF Export.

Here are some examples of Revealjs plugins packaged as Quarto extensions:

Extension Description
Pointer Adds support for switching the cursor to a ‘pointer’ style element while presenting.
Attribution Display attribution text along the right edge of slides.

Quick Start

Here we’ll describe how to create a simple Revealjs plugin extension. We’ll use the quarto create command to do this. If you are using VS Code or RStudio you should execute quarto create within their repsective integrated Terminal panes.

To get started, execute quarto create extension revealjs-plugin within the parent directory where you’d like the plugin extension to be created:

Terminal
$ quarto create extension revealjs-plugin
 ? Extension Name › shuffler

As shown above, you’ll be prompted for an extension name. Type shuffler and press Enter—the Revealjs plugin extension is then created:

Creating extension at /Users/jjallaire/quarto/dev/shuffler:
  - Created README.md
  - Created _extensions/shuffler/_extension.yml
  - Created _extensions/shuffler/shuffler.css
  - Created _extensions/shuffler/shuffler.js
  - Created .gitignore
  - Created example.qmd

If you are running within VS Code or RStudio a new window will open with the extension project.

Here’s what the contents of the files in _extensions/shuffler/ look like:

_extensions/shuffler/_extension.yml
title: Shuffler
author: J.J. Allaire
version: 1.0.0
quarto-required: ">=1.2.222"
contributes:
  revealjs-plugins:
    - name: RevealShuffler
      script:
        - shuffler.js
      stylesheet:
        - shuffler.css
_extensions/shuffler/shuffler.js
window.RevealShuffler = function () {
  return {
    id: "RevealShuffler",
    init: function (deck) {
      // TODO: Implement your plugin functionality
      // Learn more at https://revealjs.com/creating-plugins/
      
      // This example shuffles the deck when the 'T' key is pressed
      deck.addKeyBinding({ keyCode: 84, key: "T" }, () => {
        deck.shuffle();
      });
    },
  };
};

There is also a shuffler.css file for providing any styles required by your plugin.

Finally, the example.qmd file includes code that exercises the extension. For example:

example.qmd
---
title: "Shuffler Example"
format:
  revealjs: default
revealjs-plugins:
  - shuffler
---

## Breakfast

- Eat eggs
- Drink coffee

## Dinner

- Eat spaghetti
- Drink wine

To develop your plugin, render/preview example.qmd, and then make changes to shuffler.js and shuffler.css (the preview will automatically refresh when you change these files).

Installation and Use

If your extension source code it located within a GitHub repository, then it can be added by referencing the GitHub organization and repository name. For example, you can install the attribution extension with the following:

Terminal
quarto add quarto-ext/attribution

Note that it is possible to bundle and distribute extensions as simple gzip archives (as opposed to using a GitHub repository as described above). See the article on Distributing Extensions for additional details.

Once an extension has been added, you can use the Reveal plugin by adding it to the reveal-plugins key. For example:

---
title: "My Presentation"
format: revealjs
revealjs-plugins:
  - attribution
---

Plugin Packaging

Note that the plugins listed above were not initially developed for use with Quarto. Rather, they were developed intially as native Revealjs plugins and then packaged as Quarto extensions.

For example, you can find the original implementation of the attribution plugin here: https://github.com/rschmehl/reveal-plugins/tree/main/attribution. The plugin is implemented with a JavaScript file and a CSS file. To make the plugin available as a Quarto extension, we package these files along with an _extension.yml config file that registers the plugin. Here are the files in the Quarto extension:

LICENSE
README.md
example.qmd
_extensions/
   attribution/
     _extension.yml
     attribution.js
     attribution.css

Note that the LICENSE and README.md are standard documentation files and the example.qmd is used for development and documentation of the extension. None of those files are actually installed by end users (rather only the contents of the _extensions directory is installed).

You can see the full source code of the Quarto version here: https://github.com/quarto-ext/attribution (we’ll also walk through the code in detail below).

Plugin Development

You can develop either entirely new Revealjs plugins from scratch or you can package existing Revealjs extensions as described above.

Here is a list of existing 3rd party plugins for Revealjs that you might consider packaging as Quarto extensions: https://github.com/hakimel/reveal.js/wiki/Plugins,-Tools-and-Hardware.

If you want to develop new plugins, check out the Quarto Reveal extensions listed above as well as the code of other 3rd party Reveal Plugins. The following documentation on the Revealjs website provides additional important technical details:

Plugin Configuration

Some Revealjs plugins make available various user options. If you are developing a plugin from scratch, you should use a distinct key for your plugin’s configuration. Users can use this key alongside other revealjs options. For example the pointer extension can be configured as follows:

---
title: "Example Presentation"
format:
  revealjs: 
    pointer:
      pointerSize: 18
      color: '#32cd32'
revealjs-plugins:
  - pointer
---

The extension accesses options using the deck.getConfig() function:

return {
  id: "pointer",
  init: (deck) => {
    const config = deck.getConfig();
    const options = config.pointer || {};
    // etc
  }
}

Note that when packaging an existing Revealjs plugin, you can override its default configuration using the config key within your _extension.yml file. For example, these are the overrides provided by the pointer extension:

title: Pointer
author: Charles Teague
contributes:
  revealjs-plugins:
    - name: RevealPointer
      script:
        - pointer.js
      stylesheet:
        - pointer.css
      config:
        pointer:
          key: "q"
          color: "red"
          pointerSize: 16
          alwaysVisible: false

Example: Attribution

Here we’ll walk through the complete source code for the attribution extension. This extension enables you to display attribution text sideways along the right edge of Revealjs slides.

Here are source files used to develop the extension:

LICENSE
README.md
example.qmd
_extensions/
   attribution/
     _extension.yml
     attribution.js
     attribution.css

The example.qmd and documentation files are used for development of the the extension only (it is not installed by end users). The other files provide extension registration (_extension.yml) and the actual implementation of the Revealjs plugin (attribution.js and attribution.css).

The example.qmd is a simple one-slide presentation that includes an image along with a a div with class .attribution:

example.qmd
---
title: "Attribution Extension"
format: revealjs
revealjs-plugins:
  - attribution
---

## Forest Image

![](ingtotheforest.jpg)

::: {.attribution)
Photo courtesy of [@ingtotheforest](https://unsplash.com/@ingtotheforest)
:::

Note that the revealjs-plugins key references the attribution extension, which will implemented in the _extensions/attribution directory.

The _extension.yml file indicates that the extension is making available a Revealjs plugin along with the plugin name, script, and style-sheets (note that the plugin name is not arbitrary, it will be whatever name is used within the script that implements the plugin, in this case RevealAttribution):

_extensions/attribution/_extension.yml
title: Attribution
author:  Roland Schmehl
version: 0.1.0
quarto-required: ">=1.2.0"
contributes:
  revealjs-plugins:
    - name: RevealAttribution
      script:
        - attribution.js
      stylesheet:
        - attribution.css

The attribution.js file contains the implementation of the Plugin using the Revealjs Plugin API:

_extensions/attribution/attribution.js
window.RevealAttribution = window.RevealAttribution || {
  id: 'RevealAttribution',
  init: function(deck) {
      initAttribution(deck);
  }
};

const initAttribution = function(Reveal){

var ready = false;
var resize = false;
var scale = 1;

window.addEventListener( 'ready', function( event ) {

  var content;

  // Remove configured margin of the presentation
  var attribution = document.getElementsByClassName("attribution");
  var width = window.innerWidth;
  var configuredWidth = Reveal.getConfig().width;
  var configuredHeight = Reveal.getConfig().height;

  scale = 1/(1-Reveal.getConfig().margin);

  for (var i = 0; i < attribution.length; i++) {
    content = attribution[i].innerHTML;
    attribution[i].style.width = configuredWidth + "px";
    attribution[i].style.height = configuredHeight + "px";
    attribution[i].innerHTML = "<span class='content'>" + content + "</span>";
    attribution[i].style.transform = 'translate( -50%, -50% ) scale( ' + scale*100 + '% ) rotate(-180deg)';
  }

  // Scale with cover class to mimic backgroundSize cover
  resizeCover();

});

window.addEventListener( 'resize', resizeCover );

function resizeCover() {

  // Scale to mimic backgroundSize cover
  var attribution = document.getElementsByClassName("attribution");
  var xScale = window.innerWidth / Reveal.getConfig().width;
  var yScale = window.innerHeight / Reveal.getConfig().height;
  var s = 1;

  if (xScale > yScale) {
      // The div fits perfectly in x axis, stretched in y
      s = xScale/yScale;
  }
  for (var i = 0; i < attribution.length; i++) {
    attribution[i].style.transform = 'translate( -50%, -50% ) scale( ' + s*scale*100 + '% ) rotate(-180deg)';
  }
}

};

Finally, attribution.css includes the CSS that repositions and rotates the element with class .attribution on the far right side of the slide:

_extensions/attribution/attribution.css
/* Attribution plugin: text along the right edge of the viewport */
.attribution{
  position: absolute;
  top: 50%;
  bottom: auto;
  left: 50%;
  right: auto;
  font-size: 0.4em;
  pointer-events: none;
  text-align: center;
  writing-mode: vertical-lr;
  transform: translate( -50%, -50% ) scale( 100% ) rotate(-180deg);
}

/* Attribution plugin: activate pointer events for attribution text only */
.attribution .content{
  pointer-events: auto;
}