Reputation: 12102
As I am preparing tutorials for students, I need a way to hide content in collapsible panels which can be revealed by clicking on a button. I have got this to work using the code below. The RMarkdown file looks like this:
---
title: Collapsible Panel
output:
html_document:
theme: flatly
highlight: tango
---
<p>
<a class="btn btn-primary" data-toggle="collapse" href="#collapseExample1" role="button" aria-expanded="false" aria-controls="collapseExample1">
Click For Answer
</a>
</p>
<div class="collapse" id="collapseExample1">
<div class="card card-body">
```{r}
hist(1:10)
```
</div>
</div>
And it looks like this when rendered:
This works! I can also control if the code and/or results must be shown by controlling the chunk options.
But, this is not optimal because the code is messy and ugly with all the raw html. Copy-pasting this multiple times is not ideal. The ID used collapseExample1
needs to be unique every time this code block is used.
Is there some way to package this block into a reusable unit like a function or something? I am thinking something like an R function, where I can pass in code to be evaluated (or code that don't need to be evaluated), chunk options (eval
, echo
, results
, etc..) and state of the panel (open/closed).
collapsible_panel(code=NULL,echo=TRUE,results="show",state="closed")
I have many unclear questions at this point. Can I run R chunks inside R chunks? Maybe I need to use child Rmd files? Do I need to write some custom javascript?
Upvotes: 24
Views: 15996
Reputation: 1721
Another simple solution that would work (but without buttons and styling).
```{r, eval=FALSE}
hist(1:10)
```
<details>
<summary>Click for Answer</summary>
```{r, echo=FALSE, eval=TRUE}
hist(1:10)
```
</details>
And here are the two states:
Upvotes: 41
Reputation: 12102
Two slightly different methods are shown. Both approaches use only HTML and CSS. Here is the full working Rmd.
---
title: Accordion
output:
html_document
---
## Method 1
This method uses button.
```{css,echo=FALSE}
button.btn.collapsed:before
{
content:'+' ;
display:block;
width:15px;
}
button.btn:before
{
content:'-' ;
display:block;
width:15px;
}
```
```{r,echo=FALSE,results='hide'}
knitr::knit_hooks$set(drop1=function(before, options, envir) {
if (before) {
paste(
'<p>',
'<button class="btn btn-primary collapsed" data-toggle="collapse" data-target="#ce1">',
'</button>',
'</p>',
'<div class="collapse" id="ce1">',
'<div class="card card-body">', sep = "\n")
} else {
paste("</div>", "</div>", sep = "\n")
}
})
```
```{r,drop1=TRUE,results="markup"}
str(iris)
```
## Method 2
This method uses a link which behaves like a button.
```{css,echo=FALSE}
[data-toggle="collapse"].collapsed .if-not-collapsed {
display: none;
}
[data-toggle="collapse"]:not(.collapsed) .if-collapsed {
display: none;
}
```
```{r,echo=FALSE,results='hide'}
knitr::knit_hooks$set(drop2=function(before, options, envir) {
if (before) {
paste(
'<p>',
'<a class="btn btn-primary collapsed" data-toggle="collapse" href="#ce2">',
'<span class="if-collapsed">+</span>',
'<span class="if-not-collapsed">-</span>',
'</a>',
'</p>',
'<div class="collapse" id="ce2">',
'<div class="card card-body">', sep = "\n")
} else {
paste("</div>", "</div>", sep = "\n")
}
})
```
```{r,drop2=TRUE,results="markup"}
str(iris)
```
Executed R chunks can be hidden in collapsible containers (collapsed by default). The containers are defined in the R chunk options using a custom knitr hook (drop1
/drop2
). The collapsible states of the container is controlled using a button or a link (looks like a button). Custom CSS is used to change text on the button for collapsed/open states.
Upvotes: 13
Reputation: 28309
You can use multiple tabs (add {.tabset}
after the header). It's very simple to generate them using r-markdown
and they look almost the same as collapsible panel (of course you need to have more than one option).
Not to paste same code multiple times specify code
argument in chunk options (code = readLines("code.R")
). Or you can have only one panel for code and answer so you wouldn't need external document.
---
title: Collapsible Panel
output:
html_document:
theme: flatly
highlight: tango
---
# Question 1 {.tabset .tabset-fade .tabset-pills}
## Question
How does uniform distribution look like?
## Code
```{r, echo = TRUE, eval = FALSE, code = readLines("Q1.R")}
```
## Answer
```{r, echo = FALSE, eval = TRUE, code = readLines("Q1.R")}
```
Code file (Q1.R
):
hist(1:10)
To not have any content and then show answer you can make first tab completely empty with:
# Question 1 {.tabset}
## <span>​</span>
## Answer
```{r, echo = FALSE, eval = TRUE, code = readLines("Q1.R")}
```
Upvotes: 19