When we want to have two different themes in a Quarto HTML document, we can use a button to switch between light and dark mode for example. Standard the button is in the top right corner of the document. I would like to have this document below the toc of the document. Here is some reproducible code:
---
title: "Change position theme button"
format:
html:
toc: true
theme:
light: default
dark: darkly
---
## Chapter
Some text to make it reproducible
### Test
Output:
As you can see the theme switch button is in the top right corner. I was wondering how we can place it below the toc?
This is slightly trickier than I expected as the button is not placed after the table of contents (TOC) in the DOM. You can change the CSS rules, but while it will work for the example, if you have enough headings that your TOC needs to scroll, the toggle button will not float.
To achieve floating, we need to change the DOM structure to place the toggle button directly after the TOC. The toggle button is added dynamically after the page is loaded, so we need some JavaScript that watches for changes made to the DOM, e.g. a MutationObserver.
The first thing to do is add include-in-header: move-toggle.html
to your Quarto yaml. Then create move-toggle.html
which looks for changes in the DOM and moves the button if it finds it (and the table of contents is also loaded):
<script>
// function to move toggle
const moveToggle = (mutations, obs) => {
const toggleButton = document.querySelector('.quarto-color-scheme-toggle');
const toc = document.querySelector('#TOC');
// check if table-of-contents and button are loaded
if (toggleButton && toc) {
// move button (adjust as desired)
toc.after(toggleButton);
toggleButton.style.position = 'relative';
toggleButton.style.top = '0';
toggleButton.style.right = '0';
toggleButton.style.margin = '1em 0';
obs.disconnect(); // no need to keep observing
}
}
// function to observe DOM for changes
const observeDom = () => {
const observer = new MutationObserver(moveToggle);
observer.observe(document.body, { childList: true, subtree: true });
}
// observe the DOM after it has loaded
document.addEventListener("DOMContentLoaded", observeDom);
</script>
Light mode
Dark mode
For reproducibility here is the full qmd
file. The only additional line is include-in-header: move-toggle.html
.
---
title: "Change position theme button"
format:
html:
toc: true
theme:
light: default
dark: darkly
include-in-header: move-toggle.html
---
## Chapter
Some text to make it reproducible
### Test