-
Notifications
You must be signed in to change notification settings - Fork 1.9k
renderUI does not update correctly when htmlwidgets::onRender throws a JS error #4368
Description
System details
Output of sessionInfo():
R version 4.5.0 (2025-04-11 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26200)
Matrix products: default
LAPACK version 3.12.1
locale:
[1] LC_COLLATE=German_Germany.utf8 LC_CTYPE=German_Germany.utf8 LC_MONETARY=German_Germany.utf8 LC_NUMERIC=C
[5] LC_TIME=German_Germany.utf8
time zone: Europe/Berlin
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] DT_0.33 shiny_1.13.0
loaded via a namespace (and not attached):
[1] digest_0.6.39 later_1.4.7 R6_2.6.1 httpuv_1.6.16 fastmap_1.2.0 magrittr_2.0.4 cachem_1.1.0 memoise_2.0.1
[9] htmltools_0.5.9 lifecycle_1.0.5 promises_1.5.0 cli_3.6.5 xtable_1.8-8 sass_0.4.10 withr_3.0.2 jquerylib_0.1.4
[17] compiler_4.5.0 rstudioapi_0.17.1 tools_4.5.0 bslib_0.10.0 mime_0.13 yaml_2.3.12 Rcpp_1.1.1 otel_0.2.0
[25] jsonlite_2.0.0 htmlwidgets_1.6.4 rlang_1.1.6 crosstalk_1.2.2
Example application or steps to reproduce the problem
library(shiny)
library(DT)
ui <- fluidPage(
"Click buttons in this order: ",
tags$ul(
tags$li("Table"),
tags$li("Error (works)"),
tags$li("Table"),
tags$li("Error with JS bug (wrongly shows a table instead of an error view)"),
tags$li("Error (works)"),
tags$li("Error with JS bug (now it works)"),
),
actionButton("show_table", "Show Table"),
actionButton("show_error", "Show Error Message (works)"),
actionButton("show_error_js", "Show Error Message (with JS bug)"),
hr(),
h3("UI-Output 'Content'"),
uiOutput("content")
)
server <- function(input, output, session) {
view <- reactiveVal("table")
observeEvent(input$show_table, {
view("table")
})
observeEvent(input$show_error, {
view("error")
})
observeEvent(input$show_error_js, {
view("error_js")
})
output$content <- renderUI({
cat("Rendering:", view(), "\n")
if (view() == "table") {
DT::DTOutput("my_table")
} else {
div(
h2("ERROR MESSAGE", style = "color: red;"),
p("This is what you should see when clicking error buttons"),
p(paste("Current view:", view()))
)
}
})
output$my_table <- DT::renderDT({
DT::datatable(data.frame(view = view(), someData = rnorm(5))) |> htmlwidgets::onRender(htmlwidgets::JS(
switch(view(),
"table" = "function(el, x) { console.log('Table rendered OK'); }",
"error" = "function(el, x) { console.log('Error view - no JS bug'); }",
"error_js" = "function(el, x) { thisWillCauseAnError; }" # JS error
)
))
})
}
shinyApp(ui, server)Describe the problem in detail
In this app here are three buttons, one of them makes a renderUI create a DT::DTOutput and the other ones make the renderUI create a simple div without a table.
When you click those buttons as described in the app text, you will see the bug: Upon clicking on show_error_js you see a DT::datatable instead of the simple div without a table.
Some infos on why this happens: The table has a htmlwidgets::onRender event, that contains some JS code. If the JS code throws a JS error, then the renderUI fails to replace the outdated UI, despite being executed, as can be seen by the R logs.
For reference: I already discussed this behavior here: https://forum.posit.co/t/renderui-fails-to-update-when-htmlwidgets-has-js-error-is-that-a-bug/210693