Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle chunk output using "details" HTML tag

I'm writing some tutorials using blogdown. For a pedagogical reason, I want my students to think before seeing the solution. Here's my current code.

Original

---
title: "Toggle Chuck Output Using details Tag"
output: html_document
---

```{r calc, prompt=TRUE, eval=FALSE}
90 + 30
```

<details>
  <summary>Toggle output</summary>
```{r, ref.label='calc', echo=FALSE, prompt=TRUE}
```
</details>

Here's my attempt:

To avoid repeatedly writing the HTML tags, I think I need to define a function similar to ...

togglable <- function(label, summary = "Toggle output"){
  cat('<details>')
  cat(' <summary>', summary, '</summary>', sep = '')

  # Code to print output using 'ref.label' should go here.
  # The following doesn't work. 
  knitr::knit_print(knitr:::knit_code$get(label))

  cat('</details>')
}

.... then replace the <detals>...</details> block with a R code chunk similar to the following:

Use case 1 (better)

```{r usecase1, echo=FALSE, results='asis'}
togglable(label = "calc")
```

I tried to make it work, but in vain.

One more thing. If possible, I'd like this togglable() function to override the chunk options so that I don't even need to write echo=FALSE, results='asis', because the following chunk would look nicer.

Use case 2 (best)

```{r usecase2}
togglable(label = "calc")
```

In summary, I would like to ask the following questions.

  1. How can I define this togglable() function so that it behaves in the same way as the original <detals>...</details> block?
  2. Is it possible that this function overrides the options (echo and results in particular) for the chunk where this function is called? If yes, how?
  3. Alternatively, is there any other idea how to produce the result of the original code without repeatedly writing the HTML tags?

Thank you very much!

like image 432
Kenji Avatar asked Mar 28 '26 00:03

Kenji


1 Answers

This can be done by a combination of the chunk option ref.label (to reuse chunks), a chunk hook (to print the <details> tag) and a option hook (to change the chunk options when displaying the results.

---
title: "Toggle Chuck Output Using details Tag"
output: html_document
---

```{r setup, include=FALSE}
library(knitr)

knit_hooks$set(showDetails = function(before, options, envir) {
  if (before) {
    return("<details>\n")
  } else {
    return("\n</details>")
  }
})

opts_hooks$set(showDetails = function(options) {
  if(options$showDetails) {
    options$echo = FALSE
    options$results = "asis"
  }
  return(options)
})
```
  
```{r calc, prompt=TRUE, eval=FALSE}
90 + 30
```


```{r, ref.label="calc", showDetails = TRUE}
```

How it works:

  • The chunk hook is executed before and after each chunk where the option showDetails is not NULL. It prints (returns) the respective HTML.
  • The option hook adjusts the other options (echo and results) for each chunk there showDetails is TRUE.

The code could be further improved by globally setting the options of the calc chunk, such that you do not have to repeat them for all other "show code only" chunks: add opts_chunk$set(prompt = TRUE, eval = FALSE) to the setup chunk and options$eval = TRUE to the option hook.

Besides, if you want <detail> tags by default whenever using ref.label, you could use ref.label as option hook:

```{r setup, include=FALSE}
library(knitr)

opts_chunk$set(prompt = TRUE, eval = FALSE)

knit_hooks$set(showDetails = function(before, options, envir) {
  if (before) {
    return("<details>\n")
  } else {
    return("\n</details>")
  }
})

opts_hooks$set(ref.label = function(options) {
  options$echo = FALSE
  options$results = "asis"
  options$eval = TRUE
  options$showDetails = TRUE
  
  return(options)
})
```
  
```{r calc}
90 + 30
```


```{r, ref.label="calc"}
```
like image 98
CL. Avatar answered Mar 31 '26 08:03

CL.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!