tags
is an object of type list that is automatically generated inside Shiny applications, which enables the insertion of HTML tags within a user interface generated in UI.R
. This basically contains a list of functions that will transform the string argument to the content of the tag used, for example, see the following:
tags$pre("Text inside a pre tag")
This generates the following tag:
<pre>Text inside a pre tag</pre>
The complete list of tags can be found at http://shiny.rstudio.com/articles/tag-glossary.html.
Attributes can be passed to any of the functions in tags by passing them as arguments, for example:
tags$pre(align="right","Text inside a pre tag")
This will be turned into the following HTML:
<pre align="right">Text inside a pre tag</pre>
In the following UI.R
code, the previous piece of code is included. This generates a pre-tag with the text before the number insertion widget:
library(shiny) # Starting line shinyUI(fluidPage( # Application title titlePanel("Example 1"), # Sidebar with a numeric input # Sidebar sidebarLayout( sidebarPanel( tags$pre(align="right","Text inside a pre tag"), numericInput("number", "Insert a number:", value = 30, min = 1, max = 50)), #The plot created in server.R is displayed mainPanel( plotOutput("plot") ) ) ))
JavaScript can be included in a Shiny application in different ways. As script is available in the tags list, this can be included in a script
tag. This is how the UI.R
file would look like in this case:
library(shiny) # Starting line shinyUI(fluidPage( #JavaScript piece of code tags$head(tags$script(HTML("function changeColor(x,y){ x.style.backgroundColor = y;}"))), # Application title titlePanel("Example 1"), sidebarLayout( # Sidebar with a numeric input sidebarPanel( numericInput("number", "Insert a number:", value = 30, min = 1, max = 50) ), #The plot created in server.R is displayed mainPanel( plotOutput("plot") ) ) ))
In this example, it was necessary to enclose the JavaScript in HTML()
, a function that indicates that the string enclosed in it must be treated as an HTML code. Otherwise, this would be treated as normal text and consequently would not be executed.
The JavaScript code inserted produces, at this stage, no change. If the application was executed with the UI.R
file detailed previously, there would be no difference because the JavaScript code inserted is just a function declaration, but the function is not called anywhere. This function receives two arguments, an HTML element and a color name, and changes the color of the HTML element to the color passed.
As it happens with tags functions, some additional arguments can be passed to other widgets as well, which will be treated as attributes of the corresponding HTML tag. It is worth mentioning that some of these have certain restrictions with respect to the arguments they accept. In the following UI.R
code, a mouseover
and mouseout
argument will be added to sidebarPanel()
, whose value will be a call to the JavaScript function previously explained:
library(shiny) # Starting line shinyUI(fluidPage( #JavaScript piece of code tags$head(tags$script(HTML("function changeColor(x,y){ x.style.backgroundColor = y;}"))), # Application title titlePanel("Example 1"), sidebarLayout( # Sidebar with a numeric input sidebarPanel( onmouseover = 'changeColor(this,"blue")', onmouseout ='changeColor(this,"gray")', style = 'background-color: gray', numericInput("number", "Insert a number:", value = 30, min = 1, max = 50) ), #The plot created in server.R is displayed mainPanel( plotOutput("plot") ) ) ))
When a function is called inside an argument, it is not necessary to enclose the JavaScript function in HTML()
. However, it is still necessary to pass this as a string.
Scripts can be included from source too. In order to do this, the file that is called has to be stored inside the www
folder. Back to the previous example, if the function was saved in a file named change_color.js
, the corresponding call in UI.R would be as follows:
tags$head(tags$script(src="change_color.js"))
Apart from including custom JavaScript, tags are very useful to include CSS as well. CSS stands for Cascading Style Sheet and it enables the definition of specifications regarding the style of the different elements in the HTML document, such as font type, font size, background color, and text align. CSS is ideal, for example, for specifying that all divs in a page should be in red.
In general terms, the inclusion of CSS in UI.R
is similar to JavaScript; either by specifying the CSS code directly, or by reference to an external file either with an src
argument in tags$style()
or through the includeCSS()
function. For the first case, the code would be as follows:
tags$head(tags$style(HTML( "body{ background-color: LightGray;} h2{ font-family: Arial; color: red;}" )))
If we store the CSS code (the one enclosed in the HTML()
function in the following example) in a file and call it with includeCSS()
, this will done as follows:
includeCSS("example_1.css")
Although the possibility of including CSS and JavaScript in a Shiny application without needing to generate HTML from scratch enables a developer to customize almost everything in the application's UI directly from the UI.R
, functions in the tags
object can be very useful to generate other HTML tags as well (for instance, divs, titles, and so on). For example, in this piece of code, a small blue text is added after the numeric input:
sidebarPanel( numericInput("number", "Insert a number:", value = 30, min = 1, max = 50), tags$p(style="color:blue","This is some additional blue text") ),
Again, style can be passed without any problems as an argument to any function that creates a container (for example, sidebarPanel()
, mainPanel()
, tags$div()
, tags$p()
, and so on). However, when it comes to customizing inputs, for example, it is sometimes necessary to use
bootstrapPage()
instead of fluidPage()
or fixedPage()
.
In this case, passing style directly as an argument is not possible and a piece of the corresponding CSS code has to be added, in any of the preceding methods. This relies on the fact that both fluidPage()
and fixedPage()
load their own CSS stylesheet that prevail over the one given by the user. In this sense, it has to be considered that all the other style elements that come along with a fluid or fixed page will not be applied (for instance, margins). The following is an example of how the code will be in UI.R
:
library(shiny) # Starting line shinyUI(bootstrapPage( #CSS to change "number's" background color tags$head(tags$style(HTML("#number {background-color: yellow;}"))), # Application title titlePanel("Example 1"), sidebarLayout( # Sidebar with a numeric input sidebarPanel( numericInput("number", "Insert a number:", value = 30, min = 1, max = 50) ), #The plot created in server.R is displayed mainPanel( plotOutput("plot") ) ) ))
In the preceding example, the background of the input widget is yellow because the CSS code specifies that the style has to be applied to the element with ID number
. This specification is done by including #
and the ID name.
To conclude, it is worth talking about withTags()
. This is a function that refers to every function called inside it as a part of the tags object. Back to the second JavaScript example:
tags$head(tags$script(src="change_color.js"))
This is equivalent to:
withTags( head( script(src="change_color.js")))
The most important concept that underlies this section is that although sometimes the methods are not equivalent, the Shiny applications provide the possibility of performing a selective customization of almost every single item in the application's frontend without the need to code an entire HTML document, which can be a very difficult task to complete for those who are not proficient with frontend web development.
Probably the most important advantage of using R code, at least to structure the frontend, relies on the fact that the communication between the backend and the frontend is completely assured and handled directly by R without any need for special developments.