Skip to content

renderUI does not update correctly when htmlwidgets::onRender throws a JS error #4368

@Noskario

Description

@Noskario

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions