Search code examples
rshinynumeric-input

Shiny numericInput() does not respect min and max values


In Shiny, if I have a numericInput as an input, when the user manually enters a value, it is not recognizing or respecting the max/min value and allows any number.If the user selects an arrow for the dropdown it respects the values but just not when entered manually. How can I have the manual entry respect the upper/lower value bounds?

numericInput("test", label=("TestLabel"), min=0, max=10, value="", step = 1.0),

Solution

  • As @HubertL pointed out it is a reported bug.

    So you have two possibilities:

    1. Accept a small work around, see below or
    2. Wait for it to be fixed

    In case an ugly work around is useful for you until it is fixed:

    library(shiny)
    
    ui <- fluidPage(
      uiOutput("numInput"),
      textOutput("text")
    )
    
    server <- function(input, output) {
      global <- reactiveValues(numVal = 25, numMin = 1, numMax = 100)
    
      numVal <- reactive({
        if(!is.null(input$num)){
          if(input$num < global$numMin) return(global$numMin)
          if(input$num > global$numMax) return(global$numMax)     
          return(input$num)
        }else{
          return(global$numVal)
        }
      })
    
      output$numInput <- renderUI(numericInput("num", "", min = global$numMin, 
                                  max = global$numMax, value = numVal()))
    
      output$text <- renderText(input$num)
    }
    
    shinyApp(ui, server)
    

    Downside is that you cant change values as fast with the up/down "arrows".

    Edit: Request to generalize the answer for multiple inputs:

    library(shiny)
    amtInputs <- 6
    
    ui <- fluidPage(uiOutput("numInput"))
    
    server <- function(input, output) {
      global <- reactiveValues(numVal = rep(25, amtInputs), numMin = rep(1, amtInputs), 
              numMax = rep(100, amtInputs))
    
      numVal <- reactive({
        out <- rep(0, amtInputs)
        for(idNr in 1:amtInputs){
          id <- paste0("num", idNr)      
          if(!is.null(input[[id]])){
            out[idNr] <- input[[id]]
            if(input[[id]] < global$numMin[idNr]) out[idNr] <- global$numMin[idNr]
            if(input[[id]] > global$numMax[idNr]) out[idNr] <- global$numMax[idNr]
          }else{
            out[idNr] <- global$numVal[idNr]
          }
        }
        return(out)
      })
    
      output$numInput <- renderUI({
        inputs <- tagList()
        for(idNr in 1:amtInputs){
          inputs <- tagList(inputs, numericInput(paste0("num", idNr), "", 
     min = global$numMin[idNr], max = global$numMax[idNr], value = numVal()[idNr]))
        }
        return(inputs)
      })
    }
    shinyApp(ui, server)