Allow user to download shiny output in a desired directory



In my Shiny app, I run calculations, generate a data frame, and want the user to be able to save (download) it.

My relevant code in ui.R:

textInput("downFile","Save the File:", value = "Results File"),
downloadButton('downFile',"Save File")

My relevant code in server.R:

output$downFile <- downloadHandler(
  filename = function() {
    paste0(input$downFile, " ", Sys.Date(), ".csv") 
  content = function(file) {
      write.csv(MyMainFunction()$mydataframe, file, row.names = FALSE)

Everything works. But I have two issues:

  1. If by mistake the user clicks on “Save File” before all the calculations in server.R have been completed, he gets an error (“Failed - Network Error”).
  2. After all the calculations, when the user clicks on the “Save File” button, the file is immediately saved in “Downloads” folder.

Two questions:
Is it possible to make the button invisible until the calculations in my main function (MainFunction) are completed?
How could I allow the user to select a desired folder to download the results to? (as in “Save in…”)

Thank you so much!


Not sure how to change the download behavior, it always works as a “save as” by default for me. I’m not sure (and now curious) this controlled by Shiny or the user’s browser.

For the first part, I handle this in my app by generating the download button server side if there’s data to download and returning nothing if there’s nothing to download


# server.R

output$download_sim_comparison_link <- renderUI({
  } else {
    downloadLink('download_sim_comparison', p(icon("file-excel-o"), "Export Data"))

# ui.R

I have this embedded in a withSpinner() statement from the shinycssloaders package so it’s obvious why it cant be clicked when the function is executing.


Thank you, that’s nice! For the “save as” - it looks like this is indeed dictated by one’s Chrome setting - and Shiny probably can’t change that. As for hiding the button, I found this really nifty package: shinyjs.

I added this statement to my ui.R:

.... fluidRow(
  everything else as before

And I added these statements on the server side - before the calcs begin:


And then this statement after the calculations are finished: