Moving My Website to Quarto

quarto
Author

Jihong Zhang

Published

June 25, 2023

Modified

March 15, 2025

Overview

Since June 25, 2023, I start to move my website from hugo/rmarkdown/blogdown/wowchemy to quarto website. It is difficult to explain why I spend so much time on that. Perhaps because some reasons same as other bloggers: 1. Quarto is the next generation of rmarkdown. 2. Quarto is independent with R or Rstudio. 3. Quarto has a clean file tree for website building. 4. Quarto has cleaner command than hugo (i.e., quarto publish netlify for publishing website etc.).

This blog serves as a note how I customize quarto website bit by bit. It will not be a comprehensive tutorial (much online resources exists) but contain be some tricks.

2 Tricks of Quarto

2.1 Code highlighting

The very first trick is using format > html > code-fold: true settings in YAML metadata in _quarto.yml (global) or .qmd (local) to hide the code block as |> Code, like:

library(kableExtra)
kbl(head(iris)) |> 
  kable_styling(
    html_font = "Ysabeau Office",
    font_size = 11, full_width = TRUE)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa

Note that the code block can be numbered and added with a left border using code-block-bg: true and code-block-border-left: "#31BAE9"

Code block now also can be shown with language #| echo: fenced. As the code chunk shown below, {r} is explicitly presented. I don’t hate #| as the new way of chuck option setup but when I test the code chuck, I found there is a space between #| and option keys. For example, it should be #| echo: fenced rather than #|echo:fenced. Otherwise, quarto will ignore chunk options.

```{r}
#| eval: false
#| code-fold: false
kableExtra::kbl(head(iris)) |> 
  kableExtra::kable_styling(
    html_font = "Ysabeau Office",
    bootstrap_options = c('striped', 'hover'),
    font_size = 10, full_width = TRUE)
```
⌘+C
```{python}
#| eval: false
#| code-fold: show
import numpy as np
iris = np.array(iris)
```

2.2 Visual model

Visual model is one of the most appealing feature for Quarto but I am far from a expert in that. It looks like a visual model version of markdown editor (so called WYSIWYM editing, What you see is What you mean) but slightly different. The shortcut of switching between source and visual model is Cmd + Shift + F4 (Thanks to Yihui’s JS for pretty keyboard styling).

::: callout-note {#keyborad} ## Keyboard Shortcut

You can use Shortcodes keyboard shortcuts to display keyboard keys. For example, insert {{< kbd K >}} into Quarto documents displays K. {{< kbd Shift-Ctrl-P >}} display Shift-Ctrl-P after rendering. :::

I list some most frequently used keyboard for visual mode editing:

  1. Insert Hyperlink: Cmd + K

  2. Add footnote1: Shift+Cmd+F7

  3. Insert picture: Shift +Cmd +I

  4. Insert code chunk2: Alt +Cmd +I

  5. Edit attribute3: F4

1 Like this.

2 By default, it will insert R code chunk. If another language is frequently, use Tools > Modify keyboard shortcuts > filter 'Insert'. There should be a place for setting shortcut for other language.

3 Click `F4` in any place in the div works.

Please also refer to the official document for more shortcuts and features. One thing I found very interesting is single quote mark ` . First, I’m not sure how to escape this in visual model. Second, if you close quote before typing content, like ``, visual mode will escape both quote marks. However, if you type in left quote mark then content and then close quote (i.e., type in`something first, and type closing quote mark), it can quote content correctly.

Last but not least, perhaps just type / in rstudio is a better choice as it will pop up a list of elements to choose.

2.3 giscus comments box theme toggle

Important

not work any more for Quarto 1.5.23

giscus comments box needs some tweaks to switch light/dark based on the toggle switcher of quarto. Please find Ella’s post and Ella’s giscus issue discussion and original Javascript.

giscus-mode-toggle.html
<script>
function getGiscusTheme() {
  const quartoTheme = localStorage.getItem("quarto-color-scheme");
  const giscusTheme = quartoTheme === "alternate" ? "dark" : "light";
  return giscusTheme;
}

function setGiscusTheme() {
  function sendMessage(message) {
    const iframe = document.querySelector('iframe.giscus-frame');
    if (!iframe) return;
    iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
  }
  sendMessage({
    setConfig: {
      theme: getGiscusTheme(),
    },
  });
}

document.addEventListener('DOMContentLoaded', function () {
  const giscusAttributes = {
    "src": "https://giscus.app/client.js",
    "data-repo": "[ENTER REPO HERE]",
    "data-repo-id": "[ENTER REPO ID HERE]",
    "data-category": "[ENTER CATEGORY NAME HERE]",
    "data-category-id": "[ENTER CATEGORY ID HERE]",
    "data-mapping": "pathname",
    "data-strict": "0",
    "data-reactions-enabled": "1",
    "data-emit-metadata": "0",
    "data-input-position": "top",
    "data-theme": getGiscusTheme(),
    "data-lang": "en",
    "crossorigin": "anonymous",
    "async": "",
  };

  // Dynamically create script tag
  const giscusScript = document.createElement("script");
  Object.entries(giscusAttributes).forEach(([key, value]) => giscusScript.setAttribute(key, value));
  document.body.appendChild(giscusScript);

  // Update giscus theme when theme switcher is clicked
  const toggle = document.querySelector('.quarto-color-scheme-toggle');
  if (toggle) {
    toggle.addEventListener('click', setGiscusTheme);
  }
});
</script>
div-giscus.html
<div class="giscus">
include-in-header: giscus-mode-toggle.html
include-after-body: div-giscus.html
Note

Remember comment out giscus setting in _quarto.yml

#comments:
#  giscus:
#    repo: JihongZ/quarto-academic-jihong

3 Collapsing Button

There is no direct way to display a collapsing button in quarto. I found a way to do that by using bootstrap collapse component. The following code is a simple example of a collapsing button. The button is linked to a collapse component with the id collapseExample. When the button is clicked, the collapse component is shown or hidden.

For more details of bootstrap collapse component, please refer to the official documentation.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

example.qmd
[Link with href]{.btn .btn-primary role="button" title="Here's a tooltip" data-bs-toggle="collapse" href="#collapseExample" aria-expanded="false" aria-controls="collapseExample"}

:::: {#collapseExample .collapse}
::: {.card .card-body}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
:::
::::

3.1 Horizontal Collapsing

[Button with horizontal collapse]{.btn .btn-primary type="button" title="Here's a tooltip" data-bs-toggle="collapse" data-bs-target="#collapseWidthExample" href="#collapseWidthExample" aria-expanded="false" aria-controls="collapseWidthExample"}

::::: {style="min-height: 120px;"}
:::: {#collapseWidthExample .collapse .collapse-horizontal}
::: {.card .card-body style="width: 500px;"}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
:::
::::
:::::

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Back to top