Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert a popover in R Bookdown document

I have this code from an R markdown file which generates a popover. And it's working as expected:

For the R markdown document you need library(rmarkdown), library(pandoc) and pandoc_activate(). You render it with: rmarkdown::render("C:/YourPath/Popover.Rmd")

Popover.Rmd

---
title: "Test Popover"
date: "Last edited: `r format(Sys.time(), '%d.%m.%Y')`"
output: html_document
---

<script>
    $(document).ready(function(){
        // Get the text from the other element
        var textTag_1 = $('#Tag_1-source').text();
        var textTag_2 = $('#Tag_2-source').text();
        
        // Set the popover content dynamically
        $('#Tag_1').attr('data-content', textTag_1);
        $('#Tag_2').attr('data-content', textTag_2);

        // Initialize popover
        $('[data-toggle="popover"]').popover({ trigger: "hover" });
    });
</script>


# Tag definition


I want to define my tags, which I want to use:

- Keyword_Tag_1
    - <p id="Tag_1-source">
            Tag 1 describes...</p>
- Keyword_Tag_2
    - <p id="Tag_2-source">
            Tag 2 is all about...</p>

# Flowers

Flowers are ...


This section is taged with the following tags:
<a  id="Tag_1"
            data-toggle="popover" 
            data-placement="top"   
            data-content="Initial">
            Keyword_Tag_1</a>, 
<a  id="Tag_2"
            data-toggle="popover" 
            data-placement="top"   
            data-content="Initial">
            Keyword_Tag_2</a>

See the rendered result:

R markdown result with popover

Challenge: Now I want the same in a bookdown document, but it's not working. I want to define the Keyword_Tag_1, Keyword_Tag_2... in file index.Rmd and in file section1.Rmd I have some text where I want to add my tags.

Question: Perhaps you can use my skeleton and figure out what has to be added / corrected.

Here you need additional packages: library(bookdown), library(knitr), library(markdown) and library(tinytex)

You render it with: bookdown::render_book("C:/YourPath/index.Rmd", output_format = "bookdown::gitbook")

index.Rmd

---
title: "Popover in Bookdown"
date: "Last edited: `r format(Sys.time(), '%d.%m.%Y')`"
output: bookdown::gitbook
---

<script>
    $(document).ready(function(){
        // Get the text from the other element
        var textTag_1 = $('#Tag_1-source').text();
        var textTag_2 = $('#Tag_2-source').text();
        
        // Set the popover content dynamically
        $('#Tag_1').attr('data-content', textTag_1);
        $('#Tag_2').attr('data-content', textTag_2);
    
        // Initialize popover
        $('[data-toggle="popover"]').popover({ trigger: "hover" });
    });
</script>
    
    
# Tag definition
    
    
I want to define my tags, which I want to use:
    
- Keyword_Tag_1
    - <p id="Tag_1-source">
            Tag 1 describes...</p>
- Keyword_Tag_2
    - <p id="Tag_2-source">
            Tag 2 is all about...</p>

section1.Rmd

# Flowers
    
Flowers are ...
    
    
This section is taged with the following tags:
<a  id="Tag_1"
    data-toggle="popover" 
    data-placement="top"   
    data-content="Initial">
    Keyword_Tag_1</a>, 
<a  id="Tag_2"
    data-toggle="popover" 
    data-placement="top"   
    data-content="Initial">
    Keyword_Tag_2</a>
like image 989
tueftla Avatar asked Nov 22 '25 21:11

tueftla


1 Answers

There are a lot of different elements that can change how something like popover works within RMarkdown/HTML. That being said (along with how long ago you asked) this solution is not a one-size-fits-all.

Instead of trying to figure out why popover isn't working when I don't have nearly enough code of yours to evaluate it, I've provided a more fine-control version of tooltips derived from various pre-existing sources around the web (the method I personally use). This works with mobile platforms, as well.

I have used RMarkdown to render 400+ page books with words and phrases translated into another language using this method. It can be a bit time-consuming when it comes to rendering.

This essentially encapsulates your text in the necessary HTML to function as a tooltip.

So "Keyword_Tag_1" and "Tag one describes..." will become

<span class="tooltip">Keyword_Tag_1&NoBreak;<span class="tooltiptext">Tag one describes...</span></span>

Here is demonstration of what I use.

  • CSS styling
  • create tooltip HTML
  • in use example

CSS

This is definitely more than the bare minimum, but should demonstrate some of the finite control you could use, should you desire.

The classes in the CSS and what they represent:

  • :root: create a metric so that the tooltip, borders, and arrow are proportionate
  • .tooltip: the span container for both the tooltipped text and the tooltip itself
  • .tooltip > .tooltiptext: the span container for the tooltip within .tooltip
  • .tooltip > .tooltiptext::before, .tooltip > .tooltiptext::after: controls the arrow positioning 'before' and 'after' the text hovered over and the tooltip
    • .tooltip > .tooltiptext::before: essentially the entire arrow of the tooltip box
    • .tooltip > .tooltiptext::after: modifies the interior of the arrow set in ::before
  • .tooltip:hover > .tooltiptext: triggers visibility to the tooltip when you hover
  • section#section-:has(p):has(.tooltip:hover): something added specifically for bookdown::gitbook, because the section element doesn't allow overflow, meaning that if your tooltip went into the blank margins of the webpage, it's hidden; this content indicates that when hovering, make the overflow visible in the section (note that this could cause unintended changes, let me know if it causes another issue, I can help find a workaround)

Unfortunately, you can't add comments to CSS. If you have questions about the purpose of the arguments used, ask.

:root {
  --bwidth: 10px;
}
.tooltip {
  position: relative;
  display: inline;
  text-decoration: underline dotted black;
  -webkit-text-decoration: underline dotted black;
  text-underline-offset: .25rem;
  opacity: 1;
}
.tooltip > .tooltiptext{
  visibility: hidden;
  min-width: 150px;
  width: max-content;
  max-width: 400px;
  box-shadow: 5px 5px 5px rgba(0,0,0,0.2);
  background-color: #fff;
  text-align: center;
  border: calc(var(--bwidth) * .1) solid black;
  border-radius: calc(var(--bwidth) * .3);
  padding: 5px;
  position: absolute;
  bottom: 150%;
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity .3s;
}
.tooltip > .tooltiptext::after,
.tooltip > .tooltiptext::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: calc(var(--bwidth) * -1);
  border-width: var(--bwidth);
  border-left: var(--bwidth) solid transparent;
  border-right: var(--bwidth) solid transparent;
}
.tooltip > .tooltiptext::before {
  margin-bottom: calc(var(--bwidth) * -0.5);
  border-top: var(--bwidth) solid black;
}
.tooltip > .tooltiptext::after {
  margin-top: calc(var(--bwidth) * -0.1);
  border-top: var(--bwidth) solid white;
}
.tooltip:hover .tooltiptext {
  visibility: visible;
  opacity: 1;
  transform: translateX(-50%);
  position: absolute;
}
section#section-:has(p):has(.tooltip:hover) {
  overflow: visible;
}
</style>

Tooltip HTML

I created a UDF to convert text into tooltip appropriate HTML.

I used &NoBreak so that the word/phrase doesn't break across the row, causing the tooltip to hover disjointedly. (Although, it isn't strictly necessary.)

# function to build html tooltips
ttipper <- function(content, info) {
  # content: (string) word/multiword/expression adding a tooltip to
  # info: (string) tooltip to apply to the content        
  paste0('<span class="tooltip">', content,
         '&NoBreak;<span class="tooltiptext">', info,
         '</span></span>')
}

I've added comments in the code, but if anything's unclear, ask.

RMarkdown example

Here's an example of how you could use this with bookdown::gitbook as you used in your question. I have everything inline, but you can definitely import the CSS, the tooltip information, and so on.

---
title: "Untitled"
author: "me"
date: "2025-10-27"
output: bookdown::gitbook
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = F)

library(stringr)

```

<style>
:root {
  --bwidth: 10px;
}
.tooltip {
  position: relative;
  display: inline;
  text-decoration: underline dotted black;
  -webkit-text-decoration: underline dotted black;
  text-underline-offset: .25rem;
  opacity: 1;
}
.tooltip > .tooltiptext{
  visibility: hidden;
  min-width: 150px;
  width: max-content;
  max-width: 400px;
  box-shadow: 5px 5px 5px rgba(0,0,0,0.2);
  background-color: #fff;
  text-align: center;
  border: calc(var(--bwidth) * .1) solid black;
  border-radius: calc(var(--bwidth) * .3);
  padding: 5px;
  position: absolute;
  bottom: 150%;
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity .3s;
}
.tooltip > .tooltiptext::after,
.tooltip > .tooltiptext::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: calc(var(--bwidth) * -1);
  border-width: var(--bwidth);
  border-left: var(--bwidth) solid transparent;
  border-right: var(--bwidth) solid transparent;
}
.tooltip > .tooltiptext::before {
  margin-bottom: calc(var(--bwidth) * -0.5);
  border-top: var(--bwidth) solid black;
}
.tooltip > .tooltiptext::after {
  margin-top: calc(var(--bwidth) * -0.1);
  border-top: var(--bwidth) solid white;
}
.tooltip:hover .tooltiptext {
  visibility: visible;
  opacity: 1;
  transform: translateX(-50%);
  position: absolute;
}
section#section-:has(p):has(.tooltip:hover) {
  overflow: visible;
}
</style>


```{r text}

# sample text
txt = paste0("Here are some flowers' names to use tagging with.\n", 
             "Rhododendron, Baby's breath, Goldenrod, Primrose")

```

```{r helpers}

# function to build html tooltips
ttipper <- function(content, info) {
  # content: (string) word/multiword/expression adding a tooltip to
  # info: (string) tooltip to apply to the content        
  paste0('<span class="tooltip">', content,
         '&NoBreak;<span class="tooltiptext">', info,
         '</span></span>')
}

```


```{r tipContent}
# text tipped
flwr <- c("Rhododendron", "Baby's breath", "Goldenrod", "Primrose")
# tips for text
tips <- c("symbolizes danger", "symbolizes innocence", "symbolizes encouragement", 
          "symbolizes eternal love")
```


```{r applyTips}
 # for each word/phrase getting a tool tip, add tip
invisible(
  lapply(1:length(flwr), function(k) {   # replace tip with text/tip html
    # use <<- to get Global Environment
    txt <<- str_replace_all(txt, pattern = flwr[k],   
                            replacement = ttipper(flwr[k], tips[k]))
}))

```

```{r showMe, results='asis'}

cat(txt)    # display text to site

```

This renders as:

enter image description here


Of course this can be modified to change the positioning of the tooltip, tooltip arrow, make the tooltip positioning dynamic, etc.

Taking too long to render?

When I render something with a lot of text/tooltips with RMarkdown like a 400+ page translated book, within about 5-10 seconds the file extension .knit.md is created (normal part of the conversion process). Once this file is created, I use terminal/command line within or outside of RStudio to create the HTML. While the terminal method takes another 5-10 seconds, RMarkdown can take 30-45 minutes.

I've written these terminal commands for Mac, so another OS may differ. Additionally, this deletes the .md, so it's best to stop the RMarkdown render, after you run the commands in terminal.

I find it easiest to set the directory to the location of the .md first, then convert the file.

cd `~/newlocation/directory`
pandoc --standalone filename.knit.md -o filename.html

If your file name has white space or special characters, make sure you quote the file names (e.g., "filename.knit.md" instead of filename.knit.md)


Style/tooltip questions? This sandbox is useful.

like image 141
Kat Avatar answered Nov 24 '25 11:11

Kat



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!