Search code examples
cssrshinyshinywidgets

How to globally supply css to each radioGroupButtons widget in a shiny app


I have this minimal example adapted from here R shiny radiogroup Button change color:

library(shiny)

  ui = fluidPage(
    radioGroupButtons(
     # status = "primary ",  ##  you can change status value to change to select few colors
      inputId = "a",
      checkIcon = list(yes = icon("check")),
      choiceValues = 0:3,
      choiceNames = paste0(0:3),
      justified = TRUE, width = "300px"
    ),
    tags$script("$(\"input:radio[name='a'][value=0]\").parent().css('background-color', '#7EF373');"),
    tags$script("$(\"input:radio[name='a'][value=1]\").parent().css('background-color', '#E7E7E7');"),
    tags$script("$(\"input:radio[name='a'][value=2]\").parent().css('background-color', '#EDB6B2');"),
    tags$script("$(\"input:radio[name='a'][value=3]\").parent().css('background-color', '#DE6B63');"),
    
    radioGroupButtons(
      # status = "primary ",  ##  you can change status value to change to select few colors
      inputId = "b",
      checkIcon = list(yes = icon("check")),
      choiceValues = 0:3,
      choiceNames = paste0(0:3),
      justified = TRUE, width = "300px"
    ),
    tags$script("$(\"input:radio[name='b'][value=0]\").parent().css('background-color', '#7EF373');"),
    tags$script("$(\"input:radio[name='b'][value=1]\").parent().css('background-color', '#E7E7E7');"),
    tags$script("$(\"input:radio[name='b'][value=2]\").parent().css('background-color', '#EDB6B2');"),
    tags$script("$(\"input:radio[name='b'][value=3]\").parent().css('background-color', '#DE6B63');")
    )
  server = function(...) {}

  shinyApp(ui, server)

It basically colors the grouped radio buttons.

I would like to apply this colors to each radioGroupButtons Widget without using the four rows again and again.

I tried doing it with a css file in the parent directory but I don't know how to write the four rows in css e.g.

How to write:

 tags$script("$(\"input:radio[name='a'][value=0]\").parent().css('background-color', '#7EF373');"),
    tags$script("$(\"input:radio[name='a'][value=1]\").parent().css('background-color', '#E7E7E7');"),
    tags$script("$(\"input:radio[name='a'][value=2]\").parent().css('background-color', '#EDB6B2');"),
    tags$script("$(\"input:radio[name='a'][value=3]\").parent().css('background-color', '#DE6B63');"),

in the .css file and use it in the radioGroupButtons widget?


Solution

  • tags$script is used to run some JavaScript code, this is not some CSS code (tags$style is used for CSS).

    The first part of this code:

    $(\"input:radio[name='a'][value=0]\").parent().css('background-color', '#7EF373');
    

    i.e. $(\"input:radio[name='a'][value=0]\") selects one or more HTML elements. Namely, it targets all radio inputs with a name attribute equal to 'a' and a value attribute equal to 0. You can drop the part [name='a'] so that the other radio group is selected.

    If you want to put this code in an external file, create a .js file in the www subfolder containing this code:

    $(document).ready(function() {
      $("input:radio[value=0]").parent().css('background-color', '#7EF373');
      $("input:radio[value=1]").parent().css('background-color', '#E7E7E7');
      $("input:radio[value=2]").parent().css('background-color', '#EDB6B2');
      $("input:radio[value=3]").parent().css('background-color', '#DE6B63');
    });
    

    then include this file in your app by adding this code in the UI:

    tags$head(tags$script(src = "yourJSfile.js")),
    

    See here for more information about selection by attribute value.

    You could also proceed as follows:

    $(document).ready(function() {
      $("input:radio").each(function() {
        var value = $(this).attr("value");
        var color;
        switch(value) {
          case 0:
            color = "#E7E7E7";
            break;
          case 1:
            color = "#EDB6B2";
            break;
          case 2:
            color = "#AAAAAA";
            break;
          case 3:
            color = "#DE6BB3";
        }
        $(this).parent().css('background-color', color);
      });
    });
    

    Or if you want to target only these two radio groups:

    $(document).ready(function() {
      $("input:radio").each(function() {
        var name = $(this).attr("name");
        if(name === "a" || name === "b") {
          var value = $(this).attr("value");
          var color;
          switch(value) {
            ......
          }
          $(this).parent().css('background-color', color);
        }
      });
    });