Description
Describe the problem
Using update_tooltip
to update a tooltip temporarily causes HTML escaping to fail, i.e., the raw HTML string is displayed. This occurs both in R and Python Shiny. If you switch mouse focus elsewhere and then return to the tooltip, it displays HTML content as expected.
Here is a reprex in R:
library(bslib)
library(htmltools)
library(shiny)
tooltip_text_initial <- "<strong>Initial tooltip text</strong>"
tooltip_text_updated <- "<strong>Updated tooltip text</strong>"
ui <- bslib::page_fluid(
bslib::tooltip(
shiny::actionButton("btn", "A button"),
htmltools::HTML(tooltip_text_initial),
id = "tooltip"
)
)
server <- function(input, output, session) {
observe({
message("This code is triggered on a button click.")
bslib::update_tooltip(
id = "tooltip",
htmltools::HTML(tooltip_text_updated)
)
}) |>
shiny::bindEvent(input$btn)
}
shinyApp(ui, server)
App startup, hover mouse over button, showing initial text:
After clicking the button, the tooltip updates with unescaped HTML, i.e., the raw value of tooltip_text_updated
.
Switch focus from the button (click anywhere else), and the HTML escaping works as intended:
Session Info
I've tested this in Firefox, Chrome, and the built-in RStudio Viewer (RStudio versions 2024.09.0 and 2024.12.1), under R 4.4.0 and 4.4.3, and the latest stable releases of bslib and shiny. (I haven't tested the development versions because I can't see any reference to update_tooltip
in any recent dev changes.)
> devtools::session_info() ─ Session info ───────────────────────────────────────────────────────────────────────────── setting value version R version 4.4.0 (2024-04-24 ucrt) os Windows 11 x64 (build 26100) system x86_64, mingw32 ui RStudio language (EN) collate English_New Zealand.utf8 ctype English_New Zealand.utf8 tz Pacific/Auckland date 2025-05-05 rstudio 2024.09.0+375 Cranberry Hibiscus (desktop) pandoc NA
─ Packages ─────────────────────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
bslib * 0.9.0 2025-01-30 [1] CRAN (R 4.4.3)
cachem 1.1.0 2024-05-16 [1] CRAN (R 4.4.3)
cli 3.6.2 2023-12-11 [1] CRAN (R 4.4.0)
devtools 2.4.5 2022-10-11 [1] CRAN (R 4.4.1)
digest 0.6.35 2024-03-11 [1] CRAN (R 4.4.0)
ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.4.1)
fansi 1.0.6 2023-12-08 [1] CRAN (R 4.4.0)
fastmap 1.2.0 2024-05-15 [1] CRAN (R 4.4.3)
fs 1.6.4 2024-04-25 [1] CRAN (R 4.4.0)
glue 1.7.0 2024-01-09 [1] CRAN (R 4.4.0)
htmltools 0.5.8.1 2024-04-04 [1] CRAN (R 4.4.0)
htmlwidgets 1.6.4 2023-12-06 [1] CRAN (R 4.4.1)
httpuv 1.6.15 2024-03-26 [1] CRAN (R 4.4.1)
jquerylib 0.1.4 2021-04-26 [1] CRAN (R 4.4.0)
jsonlite 1.8.8 2023-12-04 [1] CRAN (R 4.4.0)
later 1.3.2 2023-12-06 [1] CRAN (R 4.4.1)
lifecycle 1.0.4 2023-11-07 [1] CRAN (R 4.4.0)
magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.4.0)
memoise 2.0.1 2021-11-26 [1] CRAN (R 4.4.0)
mime 0.12 2021-09-28 [1] CRAN (R 4.4.0)
miniUI 0.1.1.1 2018-05-18 [1] CRAN (R 4.4.1)
pillar 1.9.0 2023-03-22 [1] CRAN (R 4.4.0)
pkgbuild 1.4.4 2024-03-17 [1] CRAN (R 4.4.1)
pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.4.0)
pkgload 1.4.0 2024-06-28 [1] CRAN (R 4.4.1)
profvis 0.3.8 2023-05-02 [1] CRAN (R 4.4.1)
promises 1.3.2 2024-11-28 [1] CRAN (R 4.4.3)
purrr 1.0.2 2023-08-10 [1] CRAN (R 4.4.0)
R6 2.5.1 2021-08-19 [1] CRAN (R 4.4.0)
Rcpp 1.0.12 2024-01-09 [1] CRAN (R 4.4.1)
remotes 2.5.0 2024-03-17 [1] CRAN (R 4.4.1)
rlang 1.1.3 2024-01-10 [1] CRAN (R 4.4.0)
rstudioapi 0.16.0 2024-03-24 [1] CRAN (R 4.4.1)
sass 0.4.9 2024-03-15 [1] CRAN (R 4.4.0)
sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.4.1)
shiny * 1.10.0 2024-12-14 [1] CRAN (R 4.4.3)
stringi 1.8.3 2023-12-11 [1] CRAN (R 4.4.0)
stringr 1.5.1 2023-11-14 [1] CRAN (R 4.4.0)
tibble 3.2.1 2023-03-20 [1] CRAN (R 4.4.0)
urlchecker 1.0.1 2021-11-30 [1] CRAN (R 4.4.1)
usethis 2.2.3 2024-02-19 [1] CRAN (R 4.4.1)
utf8 1.2.4 2023-10-22 [1] CRAN (R 4.4.0)
vctrs 0.6.5 2023-12-01 [1] CRAN (R 4.4.0)
withr 3.0.0 2024-01-16 [1] CRAN (R 4.4.0)
xtable 1.8-4 2019-04-21 [1] CRAN (R 4.4.1)
The same behaviour occurs in Python Shiny; so I'm not sure whether this is a Shiny or bslib issue:
from shiny import App, reactive, ui
tooltip_text_initial = "Initial tooltip text"
tooltip_text_updated = "<strong>Updated tooltip text</strong>"
app_ui = ui.page_fluid(
ui.tooltip(
ui.input_action_button(
id="btn",
label="A button"
),
tooltip_text_initial,
id="tooltip"
)
)
def server(input, output, session):
@reactive.effect
@reactive.event(input.btn)
def update_tooltip_message():
ui.update_tooltip(
"tooltip",
ui.HTML(tooltip_text_updated)
)
app = App(app_ui, server)