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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions