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)
```
Unfortunately we have here two major problems which are the reason why the tooltips not work. However, it is solvable:
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.
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:
---
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)
```