Search code examples
rshinyshinyjs

add CSS style to selectInput choices programatically


I'm writing a shinny app, and I'm trying to change the color of the options displayed in a selectInput based on conditions. My intention is that if the option's name is "Installed", to paint it green, and if it's not, red I've tried with shinyjs::addClass() but failed.

This is what I got so far:

library(shiny)
library(shinyjs)

names <- c("A", "B", "C")
installed <- c("TRUE", "FALSE", "FALSE")

options <- data.frame(names, installed)


ui <- fluidPage(
  useShinyjs(),
  # inlineCSS("#someId .selectize-dropdown-content > .option { color: red; }"),
  # inlineCSS("#someId .selectize-input { color: red; }"),
  inlineCSS(".red {color:red;}"),
  inlineCSS(".green {color: green;}"),
  selectInput("apkgs", "Select a package", choices = options$names),
)

server <- function(input, output, session) {
  observe({
    if(input$apkgs %in% installed) {
      addClass(selector="input.apkgs", class="green")
    } else {
      addClass(selector="input.apkgs", class="red")
    }
  })
}

shinyApp(ui, server)

Solution

  • You can make a dynamic CSS style with renderUI:

    library(shiny)
    
    names <- c("A", "B", "C")
    options <- data.frame(names)
    
    cssTemplate <- function(color){
      sprintf(
        ".selectize-dropdown-content > .option,
         .selectize-input > .item 
         {
           color: %s; 
         }",
        color
      )
    }
      
    ui <- fluidPage(
      tags$head(
        uiOutput("css")
      ),
      selectInput("apkgs", "Select a package", choices = options$names),
     )
     
    server <- function(input, output, session) {
       
      output[["css"]] <- renderUI({
        color <- ifelse(input$apkgs == "A", "green", "red")
        tags$style(HTML(cssTemplate(color)))
      })
      
    }
    
    shinyApp(ui, server)
    

    EDIT by the OP

    library(shiny)
    
    names <- c("A", "B", "C")
    installed <- c(TRUE, FALSE, FALSE)
    options <- data.frame(names, installed)
    
    
    ui <- fluidPage(
      tags$head(
        uiOutput("css")
      ),
      
      div(id="algo",
          selectInput("apkgs", "Select a package", choices = options$names)
          )
    )
    
    server <- function(input, output, session) {
      output$css <- renderUI({
        tags$style(
          HTML(unlist(
            lapply(names, function(x){
              if(options[options$names==x,]$installed) {
                sprintf("#algo .selectize-dropdown-content > .option[data-value='%s'] { color: green; }", x)
              } else {
                sprintf("#algo .selectize-dropdown-content > .option[data-value='%s'] { color: red; }", x)
              }
            })
            )
          )
        )
      })
    }
    
    
    shinyApp(ui, server)