 <p>Just adding another answer that works in a similar fashion to the one by Xin, but using a package (<a href="https://github.com/daattali/shinyjs" rel="nofollow">shinyjs</a>) that natively supports enabling/disabling buttons, rather than having to deal with the messy javascript yourself. Using this package, you can simply call <code>disable("download")</code> or <code>enable("download")</code>. </p> <p>Here's a full example replicating the answer by Xin but with this package</p> <pre><code>library(shiny) library(shinyjs) runApp(shinyApp( ui = fluidPage( # need to make a call to useShinyjs() in order to use its functions in server shinyjs::useShinyjs(), actionButton("start_proc", "Click to start processing data"), downloadButton("data_file") ), server = function(input, output) { observe({ if (input$start_proc &gt; 0) { Sys.sleep(1) # enable the download button shinyjs::enable("data_file") # change the text of the download button shinyjs::text("data_file", sprintf("&lt;i class='fa fa-download'&gt;&lt;/i&gt; Download (file size: %s)", round(runif(1, 1, 10000)) ) ) } }) output$data_file &lt;- downloadHandler( filename = function() { paste('data-', Sys.Date(), '.csv', sep='') }, content = function(file) { write.csv(data.frame(x=runif(5), y=rnorm(5)), file) } ) # disable the downdload button on page load shinyjs::disable("data_file") } )) </code></pre>