Search code examples
rshinyreactable

Preserve user-specified-sorting during reactable refresh in shiny


I am making a shiny app with a reactable where the user can choose how to sort the table. The trouble is when the table refreshes the sorting goes back to the default sorting specified when the table is created. I want to be able to have the table refresh to the sorting specifications the user has chosen.

I know this is possible by using a selectInput or pickerInput or some other input along those lines which can feed to the defaultSorted argument in the reactable but I am looking for something a little bit more organic without the need of an external input. Currently the getReactableState only provides page size/number and selection references.

Below is a toy example where if the user sorts by the first 2 columns and then clicks toggle, the table refreshes and goes back to its original sort state.

library(shiny)
library(reactable)


ui <- fluidPage(
  actionButton("toggle", "Toggle"),
  reactableOutput("table")
)

server <- function(input, output, session){
  
  df <- eventReactive(input$toggle, {
    mtcars[c(1:2,sample(3:ncol(mtcars), size = 3))]
  })
  
  output$table <- renderReactable({
    reactable(df(),
              filterable = FALSE, 
              sortable = TRUE)
  })
  
}


shinyApp(ui, server)


Solution

  • You could use data argument of updateReactable:

    data should have the same columns as the original table data. When updating data, the selected rows, expanded rows, and current page will reset unless explicitly specified. All other state will persist, including sorting, filtering, and grouping state

    If you don't use rownames with your real data, this should be OK : sorting order is kept.
    If you use rownames, there seems to be an issue with rownames disappearing : this is why I put rownames in the model column below and remove rownames.

    library(shiny)
    library(reactable)
    
    
    ui <- fluidPage(
      actionButton("toggle", "Toggle"),
      reactableOutput("table")
    )
    
    server <- function(input, output, session){
      
      ref <- mtcars[c(1:2,sample(3:ncol(mtcars), size = 3))]
      ref$model <- rownames(ref)
      rownames(ref) <- NULL
      init <- ref[0,]
      
      
      output$table <- renderReactable({
        reactable(init,
                  filterable = FALSE, 
                  sortable = TRUE)
      })
      
      df <- eventReactive(input$toggle, {
       ref[sample(1:nrow(ref),20),]
      })
      
      observeEvent(input$toggle, {
        updateReactable("table", data = df())
      })
      
      
      
    }