rshiny

How to change the label color of a disabled textInput?


I do not understand how the label of a shiny textInput is properly addressed with CSS. I found many different ways of changing the label properties while searching, but while trying to adapt it to a tags$head(tags$style()) format in my ui, found that some work and some don't. I think this is important to understand when trying to change the label reactively. While I am able to change the default label color, I am unable to change it to a different color when textInput is disabled like I can for the text input field and placeholder.

library(shiny)
library(shinyjs)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  tags$head(
    #enabled settings:
    tags$style(HTML(".form-control {color:#3c8930; background:#c5e6c0;}")),
    tags$style(HTML(".form-control::placeholder{color:#7fbc75;}")),
    tags$style(HTML("#name-label {color: #3c8930;}")),
    #tags$style(HTML(".form-control-label {color: #3c8930;}")), #this does not work
    #tags$style(HTML("label.form-control-label {color: #3c8930;}")), #this does not work
    #tags$style(HTML("label.control-label {color: #3c8930;}")), #this works but changes all labels, even if they're not textInput

    #disabled settings:
    tags$style(HTML(".form-control.disabled{color:#c74545; background:#f7c2c2;}")),
    tags$style(HTML(".form-control.disabled::placeholder{color:#c17575;}")),
    #tags$style(HTML(" ... how to change the label color here?..."))
  ), 
  textInput(inputId = "name", 
            label='Label',
            placeholder = "Placeholder"),
  checkboxInput('disable','disable', value=F),
  radioButtons("name2", label="Label2",inline = TRUE, c("A", "B"))
)

server <- function(input, output, session) {
  
  observe(
    if(input$disable){
      shinyjs::disable('name')
     }else{
      shinyjs::enable('name')
    }
  )
}

shinyApp(ui = ui, server = server)

I was able to do a workaround by reactively updating the color in the observer, but in my full app I also work with shinyFeedback and those updates override any feedback coloring of the label.

library(shinyFeedback)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  shinyFeedback::useShinyFeedback(),
  tags$head(
    #enabled settings:
    tags$style(HTML(".form-control {color:#3c8930; background:#c5e6c0;}")),
    tags$style(HTML(".form-control::placeholder{color:#7fbc75;}")),
 
    #disabled settings:
    tags$style(HTML(".form-control.disabled{color:#c74545; background:#f7c2c2;}")),
    tags$style(HTML(".form-control.disabled::placeholder{color:#c17575;}")),
  ), 
  textInput(inputId = "name", 
            label=tags$p('Label', style = "color:#3c8930;", id="name_label"),
            placeholder = "Placeholder"),
  checkboxInput('disable','disable', value=F),
  radioButtons("name2", label="Label2",inline = TRUE, c("A", "B"))
)

server <- function(input, output, session) {
  
  observe(
    if(input$disable){
      shinyjs::disable('name')
      shinyjs::html("name_label", "<p style='color:#c74545'>Label</p>")
    }else{
      shinyjs::enable('name')
      shinyjs::html("name_label", "<p style='color:#3c8930'>Label</p>")
    }
  )
    
    observe(
      shinyFeedback::feedbackWarning("name", input$name2=='B', "B is selected", icon=NULL)
    )
}

shinyApp(ui = ui, server = server)

Solution

  • There are several possibilities for changing the color. One is that if the disable/enable button is clicked you change the class of the element:

    observe(
      if(input$disable){
        shinyjs::disable('name')
        shinyjs::runjs('document.getElementById("name-label").className = "control-label-disabled"')
      }else{
        shinyjs::enable('name')
        shinyjs::runjs('document.getElementById("name-label").className = "control-label"')
      }
    )
    

    This would affect only the element with id = 'name-label', but you can of course change the selector to also target other elements. Once you've done this, you can define the css for these classes, e.g.

    tags$style(HTML(".control-label {color: #3c8930;}
                     .control-label-disabled {color: #c74545;}"))
    

    and then the style will change. A complete example is below. Notice that therefore I also included another border-color for the disabled form-control since in your example there remains a small green border around the red box which one may not want to have.

    enter image description here

    library(shiny)
    library(shinyjs)
    
    ui <- fluidPage(
      shinyjs::useShinyjs(),
      tags$head(
        #enabled settings:
        tags$style(HTML(".form-control {color:#3c8930; background:#c5e6c0;}")),
        tags$style(HTML(".form-control::placeholder{color:#7fbc75;}")),
        tags$style(HTML(".control-label {color: #3c8930;}")),
        
        #disabled settings:
        tags$style(HTML(".form-control.disabled{
                            color:#c74545; 
                            background:#f7c2c2;
                            border-color:#c74545; 
                         }")),
        tags$style(HTML(".form-control.disabled::placeholder{color:#c17575;}")),
        tags$style(HTML(".control-label-disabled {color: #c74545;}"))
      ), 
      textInput(inputId = "name", 
                label='Label',
                placeholder = "Placeholder"),
      checkboxInput('disable','disable', value=F),
      radioButtons("name2", label="Label2",inline = TRUE, c("A", "B"))
    )
    
    server <- function(input, output, session) {
      
      observe(
        if(input$disable){
          shinyjs::disable('name')
          shinyjs::runjs('document.getElementById("name-label").className = "control-label-disabled"')
        }else{
          shinyjs::enable('name')
          shinyjs::runjs('document.getElementById("name-label").className = "control-label"')
        }
      )
    }
    
    shinyApp(ui = ui, server = server)