Collapsable Multi-Cell Blocks in Quarto Output of .ipynb

Life
Useful
Surprisingly easy!
Author

Bailey Andrew

Published

January 9, 2023

In JupyterLab, we can collapse all cells underneath a header, which can be useful for hiding extraneous info. However, when we render it in Quarto the collapsability is not preserved. It would be nice if we could recreate this feature!

Quarto does offer some methods for collapsing:

The first is <details> html blocks. These are my preferred method because it is pure html and thus highly customizable.

Which I don’t use because it’s not pure html, and thus doesn’t render in the notebook - it only appears after rendering with Quarto.

The quarto method has the benefit that it can be split over multiple cells, allowing the collapsing of code cells:

print("It worked!")
[1] "It worked!"
Messing around with Quarto

There’s a major problem, though; the Quarto method looks a little too professional… I want the callout blocks to have the same appearance as a <details> tag!

The first step we can do is add a class to our callout block:

Test

The markdown to generate is:

::: {.callout-tip collapse="true" #custom-callout}
  <h2>Test</h2>
  <! -- ETC... -->
:::

To make that work, I used a fairly advanced bit of CSS:

First, create a file blocks.css, into which you’ll put the style, and then add this to the Quarto header:

format:
  html:
    css: blocks.css

Fill the css file with the following:

.callout-tip #custom-callout :is(h1, h2, h3, h4, h5, h6) {
  color:#C0CF96
}

This says “for all objects with the callout-tip class and the custom-callout id, check if any of their children are h1 or h2 or (…) or h6. If so, give them this specific color.”

It’s not perfect, though - as the header (“Test”) no longer shows up on the title but rather only appears when you open the drop-down.

The markdown to generate is:

::: {.callout-tip collapse="true" #custom-callout2}
  ## Test
  <! -- ETC... -->
:::

We can start poking around with inspect element to get the classes we need to mess with in the CSS:

#custom-callout2 div.callout-caption-container.flex-fill {
  color:#C0CF96;
  font-weight:bold;
}
#custom-callout2 div.callout-icon-container {
  opacity:0%;
}

All that’s left is to remove the pesky background:

The markdown to generate is:

::: {.callout-tip collapse="true" #clean-collapse}
  ## ▶ Test
  <! -- ETC... -->
:::
print("Running code just to demonstrate it still works")
[1] "Running code just to demonstrate it still works"

I added the following CSS:

#clean-collapse div.callout-caption-container.flex-fill {
  color:#C0CF96;
  font-weight:bold;
}

#clean-collapse div.callout-icon-container {
  opacity:0%;
}

And to get rid of the background I had to remove the callout-style-default class using JavaScript:

<script>
  element = document.getElementById("clean-collapse");
  element.classList.remove("callout-style-default");
</script>

Which can just be put anywhere on the page - probably it will make sense to make a .js file that will contain all of these scripts, such as this and the comments scripts, and paste them on each page.

However, the fatal flaw with this method - that can only ever edit one dropdown at once, and it requires you to manually add arrows. To fix this, we can do more sophistic JavaScript:

<script>
    // Remove background
    elements = document.querySelectorAll('[id=clean-collapse]').forEach(
        function(element) {
            element.classList.remove("callout-style-default");
        }
    )
    
    // Add arrow to front to signify dropdownyness
    arrow = "▶";
    elements = document.querySelectorAll('.callout-caption-container').forEach(
        function(element) {
            element.innerHTML = arrow + element.innerHTML;
        }
    )
</script>

I took this opportunity to refactor the website, so that I don’t need to put comments, css, and javascript at the end of every webpage, rather I can do it by including premade files, like so:

---
title: "Collapsable Multi-Cell Blocks in Quarto Output of .ipynb"
description: "Surprisingly easy!"
author: "Bailey Andrew"
date: "Jan 9 2023"
draft: false
categories: [Work, Useful]
format:
  html:
    css:
      - ../../html_scripts/collapse.css
      - ../../html_scripts/pretty_shortcuts.css
    include-after-body: 
      - ../../html_scripts/collapse.html
      - ../../html_scripts/comments.html
---

But in fact you don’t need to mess around with the Quarto way, because the <details> tag works multi-line as well - that’s how I hid all the “playing around with quarto” stuff.