Hi Yihui, pursuant to the discussion on Twitter, I'm writing to request the capability for a table of contents in Xaringan. Thank you!
By filing an issue to this repo, I promise that
xfun::session_info('xaringan'). I have upgraded all my packages to their latest versions (e.g., R, RStudio, and R packages), and also tried the development version: remotes::install_github('yihui/xaringan').I understand that my issue may be closed if I don't fulfill my promises.
I think the TOC could be dynamically generated by JavaScript. I don't have time for it, but I think it is an excellent JS exercise. I'll leave it to other contributors. I'm not sure how long it will take, but for me, I guess it would take less than an hour.
Implementation-wise: use JS to find all h[1-6] header elements (.querySelectorAll()) and generate a bullet list (<ul>) on a slide with a certain attribute (e.g. class: toc). There needs to be a mechanism (e.g. class: no-toc or `.no-toc[# header]`) to exclude certain headers because some of them may not really be headers.
This feature can also be as fancy as beamer: there could be multiple TOC slides, and each TOC fades out the headers that appear before this TOC page, so only headers that have not yet been talked about are highlighted. Or only highlight the next header, like \tableofcontents[currentsection] in beamer.
Hey @EvaMaeRey you can try my solution on following SO question.
Cool. That seems like a good approach!
@EvaMaeRey there's also this
@step- I am aware of that but I couldn't set it up properly, do you have a minimum working example of that?
@markushhh no, not really. However, inspired by your script, I wrote this hack:
I have a working prototype, which I'll attempt to document here.
toc.html that imports jQuery and contains the JavaScript to identify h2 headers.<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous">
</script>
<script>
$(document).ready(function() {
var h2 = $( ":not(.toc) > h2" );
var items = h2.map(
function(){return $(this).text()}
).get()
items.shift(); // Remove first item (title)
items.pop(); // Remove last item (spurious???)
var item_list = items.join("</li><li>");
var toc = "<ul><li>" + item_list + "</li></ul>";
$(".toc > h2").after(toc);
});
</script>
toc.html to your xaringan yaml header:output:
xaringan::moon_reader:
includes:
in_header:
- 'toc.html'
toc:class:toc
## Table of Contents
---
This script will read all the h2 entries, except on the slide with class toc, and then insert a <li> with these entries after the h2 heading on that page.

By the way, there has to be a better way to insert JavaScript into xaringan, but I couldn't find it. So I opened a question at RStudio Community.
Have you tried the beforeInit field?
@pat-s beforeInit may not be a good choice in this case: https://community.rstudio.com/t/40348/3
In the list of remark.js plugins, there is a table of contents plugin, remark-toc.
Is there a way to include the plugins into xaringan?
That remark.js is not our remark.js.
Most helpful comment
Hey @EvaMaeRey you can try my solution on following SO question.