2

I am looking to change the colour of the actual individual check boxes from the standard shiny blue in checkboxGroupInput.

I have found the following code as an answer to this question Coloring the checkboxGroupInput choices which will change the colour of the font but not the checkbox themselves.

library("shiny")

ui <- fluidPage(
  checkboxGroupInput(
    inputId = "my_cbgi",
    label = "Choose Something", 
    choiceNames = list(
      tags$span("A", style = "color: red;"),
      tags$span("B", style = "color: red;"), 
      tags$span("C", style = "color: blue;"), 
      tags$span("D", style = "font-weight: bold;")
    ),
    choiceValues = c("A", "B", "C", "D")
  )
)

server <- function(input, output) {

}

shinyApp(ui = ui, server = server)

Is there a way to modify this to change the colour of individual checkboxes? Thanks in advance for your help.

patalt
  • 465
  • 3
  • 10
person
  • 96
  • 12
  • Please look at this https://stackoverflow.com/questions/35073318/change-colour-of-checkboxes-in-shiny-checkboxgroupinput – YBS Jun 19 '20 at 00:57

2 Answers2

3

You can do as follows with prettyCheckboxGroup of the shinyWidgets package:

library(shiny)
library(shinyWidgets)

items <- c("One", "Two", "Three")

CSS <- "
/* CSS for the labels */
.pretty input[value=One]~.state span {
  color: red;
  font-weight: bold;
}
/* CSS for the checkboxes */
.pretty input[value=One]~.state label:after, 
.pretty input[value=One]~.state label:before {
  background-color: red;
}
.pretty input[value=Two]~.state label:after, 
.pretty input[value=Two]~.state label:before {
  background-color: green;
}
.pretty input[value=Three]~.state label:after, 
.pretty input[value=Three]~.state label:before {
  background-color: blue;
}
/* CSS for the checked checkboxes */
.pretty.p-default input:checked~.state label:after {
  background-color: yellow !important;
}
"

ui <- fluidPage(
  tags$head(tags$style(HTML(CSS))),
  h1("Hello World"),
  prettyCheckboxGroup("numbers", label="Choose numbers", 
                      choiceNames = items, choiceValues = items, 
                      selected = items),
  verbatimTextOutput("value")
)

server <- function(input,output,session){
  output$value <- renderText(input$numbers)
}

shinyApp(ui, server)
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
1

The short answer to your question is that this is not very straight-forward to do and if you're not willing to directly mess with HTML and CSS, I would recommend you don't waste time on this.

To generate the container for the checkboxes checkBoxGroupInput uses shiny:::generateOptions under the hood. A look at the source shows that unfortunately changing the style of individual checkboxes is not easy, because by default it applies the same class="checkbox" to each div (the answer pointed to in the comment only explains how to set a default style for all choices).

The only remedy I can see is to insert raw HTML directly into your UI. Even this is complicated by the fact that you "still can't apply styles (borders, etc.) directly to the checkbox element and have those styles affect the display of the HTML checkbox" as per the answer in the comment. I'm fairly new to CSS myself, but from searching through the linked references, this essentially means that you have to create the HTML checkbox from scratch and overlay the default one (apparently you can hide the default one but I haven't succeeded in that).

With all that said below you'll find a working example for your case and the output it generates beneath the code. Note that I'm using separate wrappers (.my_checkBox_red,.my_checkBox_blue and .my_checkBox_grey) in each case. There is probably a way to do this more efficiently by just changing the relevant styles (colour:, background-colour:), but I couldn't figure this out. Also, one thing that can definitely be done quite easily to improve the below is to automate the generation of the long HTML string, but I don't have time to do this now. If you want to have a go yourself, the shiny function checkBoxGroupInput and shiny:::generateOptions might be a good starting point or just build your own function using sprintf, paste, ...

Hope this helps!

library("shiny")

ui <- fluidPage(
  # The below now creates a custom css class. 
  tags$head(
    tags$style(HTML('
      .my_checkBox_red input[type="checkbox"]:before {
          border: 2px solid;
          color: red;
          background-color: white;
          content: "";
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
      
      .my_checkBox_red input[type="checkbox"]:checked:after {
          border: 2px solid;
          color: red;
          background-color: #ffcccc;
          content: "✓";
          font-size: smaller;
          vertical-align: middle;
          text-align: center;
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
      
      .my_checkBox_blue input[type="checkbox"]:before {
          border: 2px solid;
          color: blue;
          background-color: white;
          content: "";
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
      
      .my_checkBox_blue input[type="checkbox"]:checked:after {
          border: 2px solid;
          color: blue;
          background-color: #ccccff;
          content: "✓";
          font-size: smaller;
          vertical-align: middle;
          text-align: center;
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
      
      .my_checkBox_grey input[type="checkbox"]:before {
          border: 2px solid;
          color: grey;
          background-color: white;
          content: "";
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
      
      .my_checkBox_grey input[type="checkbox"]:checked:after {
          border: 2px solid;
          color: grey;
          background-color: #e6e6e6;
          content: "✓";
          font-size: smaller;
          vertical-align: middle;
          text-align: center;
          height: 15px;
          left: 0;
          position: absolute;
          top: 0;
          width: 15px;
      }
    '))
  ),
  tags$div(
    HTML(
      '<div id="my_cbgi" class="form-group shiny-input-checkboxgroup shiny-input-container">
        <label class="control-label" for="my_cbgi">Choose Something</label>
        <div class="shiny-options-group">
          <div class="my_checkBox_red">
            <div class="checkbox">
              <label>
                <input type="checkbox" name="my_cbgi" value="A"/>
                <span><span style="color: red;">A</span></span>
              </label>
            </div>
          </div>
          <div class="my_checkBox_red">
            <div class="checkbox">
              <label>
                <input type="checkbox" name="my_cbgi" value="B"/>
                <span><span style="color: red;">B</span></span>
              </label>
            </div>
          </div>
          <div class="my_checkBox_blue">
            <div class="checkbox">
              <label>
                <input type="checkbox" name="my_cbgi" value="C"/>
                <span><span style="color: blue;">C</span></span>
              </label>
            </div>
          </div>
          <div class="my_checkBox_grey">
            <div class="checkbox">
              <label>
                <input type="checkbox" name="my_cbgi" value="D"/>
                <span><span style="font-weight: bold;">D</span></span>
              </label>
            </div>
          </div>
        </div>
      </div>'
    )
  ),
  textOutput("choice")
)

server <- function(input, output) {
  output$choice = renderText({
    input$my_cbgi
  })
}

shinyApp(ui = ui, server = server)

enter image description here

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
patalt
  • 465
  • 3
  • 10