I’m building a simple Shiny App, and have a decent understanding (or so I thought) of CSS and how to use it to style different UI elements (background color, size, etc.).
The issue I’m having is that I’m using renderUI()
a lot in my app, because I need the inputs to be reactive to one another. When I move the selectInput()
from the ui
portion of the app into the server
section (and use it inside renderUI()
), it now seemingly ignores the CSS. What gives?
Here’s the first example, NOT using renderUI()
, and the CSS (in this case, just a smaller 6px font-size for the selectInput()
text) works fine:
library(shiny)
ui <- fluidPage(
tags$head(tags$style(HTML('.selectize-input {font-size: 6px;}'))),
shiny::selectInput("input_1", label = NULL, choices = c("a", "b", "c"))
)
server <- function(input, output, session){}
shinyApp(ui = ui, server = server)
Then I move the selectInput()
call into a renderUI()
function in the server
section, and the CSS doesn’t get applied, even though I’m not changing that part at all. Shouldn’t the CSS rules still be applied to all .selectize-input
elements?
library(shiny)
ui <- fluidPage(
tags$head(tags$style(HTML('.selectize-input {font-size: 6px;}'))),
shiny::uiOutput(outputId = "output_1")
)
server <- function(input, output, session){
output$output_1 = shiny::renderUI({
shiny::selectInput("input_1", label = NULL, choices = c("a", "b", "c"))
})
}
shinyApp(ui = ui, server = server)
2
Answers
When I run your code in RStudio I see that your css value is being overridden.
Why it is occurring in one and not the other I’m not sure.
Perhaps instead of inline css, use a style sheet and add an additional class to your dropdown to ensure it selects? Or add further classes such as the .selectize-dropdown etc to increase its priority.
Edit: Try this
In the
head
tag of anHTML
document generally the order matters, e.g. if you have multiple stylesheets.Shiny
constructs thehead
tag in a sense of ‘as needed’.In your first example where you don’t render something inside the
server, the
head
tag looks like this:Your custom style is loaded at the end and hence
overwrites the
selectize
styles.However, in your second example, where you use
renderUI
around theselectInput
inside the server and then put anuiOutput
in theui
, thehead
tag has this order:Your custom style gets overwritten by the
selectize
styles (here:font-size: inherit
). The order isexpectable because your own styles may need to be relevant before the
selectInput
gets rendered (it is not rendered ‘immediately’).While it is a possibility to edit the
CSS
in combination with e.g. adding additional classes, this may not be the most desirable approach in particular in larger apps where you have a lot of custom styles. If it is suitable for you that in the second example the order of thehead
tag is the same as in the first example, one approach to set this would be like this:shiny
has a function insertUI() which can be used for adding arbitraryUI
elements into the app, and below theui
is an htmltools::htmlDependency() which contains the custom style without additional editing. It gets loaded after theselectize
styles. There might be a more straightforward method, though.