daattali/shinyjs

Feature request - add more documentation/examples for addCssClass / removeCssClass / toggleCssClass

jzadra opened this issue · 2 comments

I'm struggling a bit with the add/remove/toggle class/Cssclass functions. It would be great to have a bit more documentation regarding the arguments and a few other things:

  • For toggle, how is the default (pre-toggle) defined? Can it be in styles.css? Or should it be in inlineCSS?
  • Are both id and class arguments required, or just one or the other?
  • for the inlineCSS list, are the names arbitrary and just need to match the first argument of toggleClass?
  • For id selectors, does it require the hash mark?

In the documentation for these, the following example is given:

if (interactive()) {
  library(shiny)

  shinyApp(
    ui = fluidPage(
      useShinyjs(),  # Set up shinyjs
      # Add a CSS class for red text colour
      inlineCSS(list(.red = "background: red")),
      actionButton("btn", "Click me"),
      p(id = "element", "Watch what happens to me")
    ),
    server = function(input, output) {
      observeEvent(input$btn, {
        # Change the following line for more examples
        toggleClass("element", "red")
      })
    }
  )
}

The inclineCSS definitions apply to the top level css for background (or text if color: white;) is added, but it isn't clear how to specify a specific class like a panel. Further documentation on how to change more specific css classes would be helpful.

For context, thishis is coming up because I have an absolutePanel for which I want to change the background color. I have it set to a white background along with some other properties in my styles.css. I have been unable to affect a change in background color using a variety of versions of calls to add/remove/toggle.

UI excerpts:

useShinyjs(),
  tags$head(includeCSS("styles.css")),
   inlineCSS(list(.panel_dark = ".panel-default {
                 background-color: grey !important;
}"
                 )),

#...
absolutePanel(class = "panel-default", fixed = TRUE,
                draggable = T, top = 20, left = "auto", right = 20, bottom = "auto",
                width = 400, height = "auto",
                
                h4(id = "medoid_element", "Cluster Medians"),
                
                plotlyOutput("fingerprint_plot"),
                
                
  )

styles.css:

.panel-default {
  background-color: white;
padding: 0 20px 20px 20px;
cursor: move;
  opacity: 0.85;
zoom: 0.9;
transition: opacity 500ms 1s;
}

server:

observe({
   toggleClass(class = "panel_dark", condition = input$themeToggle)
})

I have tried numerous variations of this including setting an ID for the panels. It just isn't clear where the connection is between the inlineCSS definition, the call to toggleCss as far as the class argument, and whether or not to include the default (ie pre-toggle state) of the panel in styles.css or elsewhere.

  • There is no "pre"-toggle defined. Just like the toggle() and toggleState() functions, toggleCssClass adds a specified CSS class to an element if the class does not currently exist, and it removes it if it does exist. There is no comlex logic, if the class is already on the element then it's removed, otherwise it's added. Here's a new example to help show this:

    library(shiny)
    
    ui <- fluidPage(
      shinyjs::useShinyjs(),
      tags$style(".red { color: #ff0000; }"),
      div(id = "changeme", "changeme"),
      actionButton("test", "test")
    )
    
    server <- function(input, output, session) {
      observeEvent(input$test, {
        shinyjs::toggleCssClass("changeme", class = "red")
      })
    }
    
    shinyApp(ui, server)

    Every time you press the button, you're toggling the "red" class on the <div>. In this example the div happens to not have that class initially, so the first time you click it the class is added, then removed, then added, etc. If you replace the <div> line above with div(id = "changeme", "changeme", class = "red"), then now the class will exist initially, so the first toggle will remove it, then add it, then remove, etc.

    That's the basic behaviour of toggle - a simple back and forth depending on the current state. You can also use the condition argument to explicitly set whether the it should be on or off (this is explained in detail in the documentation).

  • class is required because that's the class name that you want to toggle. You need to provide either id or selector. id is just a convenience argument so that you wouldn't have to add the hashtag yourself (and it also deals with shiny module namespaces). In other words, the id or selector identify the element, and class is the class to add/remove to that element.

  • inlineCSS is unrelated to the toggle functions, hence it has a separate documentation entry. This function is a way to add CSS into your shiny app without having to import a stylesheet file or writing out a <style> tag. All the rules you define there are arbitrary in the sense that it's the same CSS rules you would define in a regular css file/style tag.

  • For the selector parameter, you use the same format as a CSS selector. So yes, you need to add a hashtag for IDs (but if you want to target an element by ID, you can use the id parameter instead for convenience. It's the same effect, but with selector you can target any element, not only by id)

The css definitions are added to the entire page, not to a specific element. You can target specific elements with your CSS rule, but the CSS rule itself will work on anything in the page that matches the selector. I looked at the documentation again now and I do think it's quite comprehensive, you may benefit from some CSS tutorials if it's still unclear.

Thanks for the detailed response! I do need to learn more CSS.