rknitrquartokableextra

Adding tooltips or popovers to table generated with `kableExtra` in an R quarto document


I want to add tooltips or popovers to HTML tables in Quarto, but got stuck, after reading the documentation and considerable trial and error. Links work as expected, but tooltips or popover messages don't show up.

File foo.qmd:

---
format: html
---


<script>
$(document).ready(function(){
    $('[data-toggle="popover"]').popover(html: true); 
});
</script>


```{r}
library(kableExtra)
library(dplyr)
library(tibble)

## example data
dt <- mtcars[1:6, 1:3] |>
  rownames_to_column(var = "car") |>
  remove_rownames() |>
  mutate(link="link")

POP  <- paste("lorem ipsum", LETTERS[1:6])
LINK <- paste0("https://example.org/page",1:6,".html")

dt |>
  mutate(car  = cell_spec(car, "html", popover = spec_popover(content=POP)),
         link = cell_spec(LINK, "html", link=LINK)) |>
  kbl(format = "html", escape = FALSE)
```


Solution

  • Unfortunately we have here two major problems which are the reason why the tooltips not work. However, it is solvable:

    1. kableExtra ships a JS dependency on a small script kePrint.js which activates what you define via spec_popover. However, this is written in jQuery and Quarto does not include a jQuery dependency so one gets a JavaScript error within the document. In R Markdown this problem does not occur because there the jQuery dependency is included.

      So what we have to do is to include a jQuery dependency. While Quarto provides a possibility to use include-in-header, this won't work here because then jQuery is appended at the end of the header and we need it before kePrint.js. A convenient possibility is given via jquerylib (also used in R Markdown, see above) and can be included in the R code via

      #install.packages("jquerylib")
      jquerylib::jquery_core(3)
      

      (However, note that there are also other possibilities, this is just a wrapper for htmltools::htmlDependency().) It includes jQuery on the right place inside the header and solves the JS error.

    2. kableExtra defines popover which are not suitable for Bootstrap 5, however, Quarto ships a Bootstrap 5 dependency. E.g.

      kableExtra::spec_popover()
      # [1] "data-toggle=\"popover\" data-container=\"body\" data-trigger=\"hover\" data-placement=\"right\"  data-content=\"\""
      

      is problematically because we e.g. need data-bs-toggle as an attribute. There are more problems, for example, Bootstrap (5) has a click event as default for a popover and this overwrites what comes from kableExtra.

      What I did in the minimal example below is that I rewrote the Javascript such that it makes the necessary adjustments on the popover such that it works. Please see the Bootstrap docs for more details on customization options.

    The code below yields this:

    enter image description here

    ---
    format: html
    ---
    
    <script>
    $(document).ready(function(){
      $('[data-toggle="popover"]').each(function() {
        var $t = $(this);
        $(this).attr({
          'data-bs-toggle': $t.attr('data-toggle')
        })
        .removeAttr('data-toggle')
        .attr({
          'data-bs-content': $t.attr('data-content')
        })
        .removeAttr('data-content')
        .attr({
          'data-bs-trigger': $t.attr('data-trigger')
        })
        .removeAttr('data-trigger')
        .attr('data-bs-title', '""')
        .popover({trigger: "hover", html: true})
      }); 
    });
    </script>
    
    
    ```{r, echo = FALSE, message = FALSE}
    
    #install.packages("jquerylib")
    jquerylib::jquery_core(3)
    
    library(dplyr)
    library(tibble)
    library(kableExtra)
    
    ## example data
    dt <- mtcars[1:6, 1:3] |>
      rownames_to_column(var = "car") |>
      remove_rownames() |>
      mutate(link="link")
    
    POP  <- paste("lorem ipsum", LETTERS[1:6])
    LINK <- paste0("https://example.org/page",1:6,".html")
    
    dt |>
      mutate(car  = cell_spec(car, "html", popover = spec_popover(content=POP)),
             link = cell_spec(LINK, "html", link=LINK)) |>
      kbl(format = "html", escape = FALSE)
    ```