title: Dynamically add/remove whole UI elements in Shiny
body: <p>I've been trying to generate a Shiny page where elements can be added or removed by the user - based on <a href="https://gist.github.com/beader/bbf2221ab6f84a819c0f" rel="nofollow noreferrer">this snippet</a>. I tried to adapt it for UI elements rather than buttons, but I've clearly done something wrong. </p>
  
  <p>I've only included the add-button part here - each time the "add" button is clicked, the correct number of UI elements are added, but they seem to all be the same element rather just appending a new one to the existing list (the number in the label is the same, whereas it should be different for each one) and the initial text values are erased (or, potentially, are just the "default" from the final element repeated however many times).</p>
  
  <p>How can I just add a new UI element and keep any text input that the user has entered in the already-existing elements?</p>
  
  <p>Code:</p>
  
  <pre><code>library(shiny)
  
  # function to render UI element
  
  renderUiElement &lt;- function(id, nameDef) {
    renderUI(box(
      actionButton(paste0("rmBtn", id), label = "", icon = icon("times")),
  
      # text initial value supplied as a variable
  
      textInput(paste0("nameText", id), label = paste("Item", id), value = nameDef)
    ))
  }
  
  
  server &lt;- function(input, output, session) {
  
    rv &lt;- reactiveValues(uiComponents = list(), uiIds = list(), 
                         nameVals = list(), lastId = 0)
  
    # on "Add" button click: 
  
    observe({
      if(is.null(input$addBtn) || input$addBtn == 0) return()
  
      isolate({
  
        # store current text inputs and append new default text
  
        rv$nameVals &lt;- lapply(rv$uiIds, function(x) input[[paste0("nameText", x)]])
        rv$nameVals &lt;- append(rv$nameVals, "New Text")
  
        # create (and store) new id number and add it to the list of ids in use
  
        rv$lastId &lt;- rv$lastId + 1 # get the new code to use for these UI elements
        rv$uiIds &lt;- append(rv$uiIds, rv$lastId)
  
        # for each id, render the UI element using the appropriate default text
  
        for(i in seq_along(rv$uiIds)) {
          thisId &lt;- rv$uiIds[[i]]
          output[[paste0("uiEl", thisId)]] &lt;- renderUiElement(
            id = thisId, nameDef = rv$nameVals[[i]]
          )
        }
  
        # add the new UI element into the reactiveValues list
  
        rv$uiComponents &lt;- append(
          rv$uiComponents, 
          list(
            list(
              uiOutput(paste0("uiEl", rv$lastId)),
              br(),br()
            )
          )
        )
      })
    })
  
    # render all the UI elements inside the container
  
    output$container &lt;- renderUI({
      rv$uiComponents
    })
  
  }
  
  ui &lt;- fluidPage(
    titlePanel("Dynamically Add/Remove UI Elements"),
    hr(),
    actionButton("addBtn", "Add"),
    br(),br(),
    uiOutput("container")
  )
  
  shinyApp(ui, server)
  </code></pre>