Shiny by RStudio

Customize your UI with HTML

In this article, you will learn how to supplement the functions in ui.R with raw HTML to create highly customized Shiny apps. You do not need to know HTML to use Shiny, but if you do, you can use the methods in this article to enhance your app.

The user-interface (UI) of a Shiny app is web document. Shiny developers can provide this document as an index.html file or assemble it from R code in a ui.R file.

ui.R calls R functions that output HTML code. Shiny turns this code into a web app.

I will use the 01_hello app throughout this article as an example. You can access this app by running:

library(shiny)
runExample("01_hello")

shinyUI

Many Shiny apps come with a ui.R script that determines the layout of the app. The ui.R script for 01_example looks like the following code:

library(shiny)

# Define UI for application that draws a histogram
shinyUI(fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
))

The code creates this app:

01_hello

Each ui.R script calls the function shinyUI. shinyUI then calls R functions that return HTML. In other words, Shiny lets you generate HTML with R. This is why you do not need to know HTML to use Shiny.

You can see that the functions inside of shinyUI return HTML if you run them. fluidPage returns a chunk of HTML as does every function inside of fluidPage. For example, the following code returns the HTML output in the comments below.

fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

## <div class="container-fluid">
##   <h2 style="padding: 10px 0px;">Hello Shiny!</h2>
##   <div class="row-fluid">
##     <div class="span4">
##       <form class="well">
##         <div>
##           <label class="control-label" for="bins">Number of bins:</label>
##           <input id="bins" type="slider" name="bins" value="30" class="jslider" data-## from="1" data-to="50" data-step="1" data-skin="plastic" data-round="FALSE## " data-locale="us" data-format="#,##0.#####" data-smooth="FALSE"/>
##         </div>
##       </form>
##     </div>
##     <div class="span8">
##       <div id="distPlot" class="shiny-plot-output" style="width: 100% ; height: ## 400px"></div>
##     </div>
##   </div>
## </div> 
titlePanel("Hello Shiny!")
## <h2 style="padding: 10px 0px;">Hello Shiny!</h2>

In R terminology, the output is a list of character strings with a special class that tells Shiny the contents contain HTML.

class(titlePanel("Hello Shiny!"))
## [1] "shiny.tag.list" "list" 

Shiny’s UI functions are sufficient for creating most Shiny apps. In 90% of your Shiny apps, you will probably never think of using anything more complicated. However in some apps, you may want to add custom HTML that is not provided by the usual Shiny functions. You can do this by passing HTML tags to shinyUI with the tags object.

tags

shiny::tags is a list of 110 functions. Each function builds a specific HTML tag. If you are familiar with HTML, you will recognize these tags by their names. You can learn what the most common tags do in the Shiny HTML tags glossary.

names(tags)
##   [1] "a"           "abbr"        "address"     "area"        "article"
##   [6] "aside"       "audio"       "b"           "base"        "bdi"
##  [11] "bdo"         "blockquote"  "body"        "br"          "button"
##  [16] "canvas"      "caption"     "cite"        "code"        "col"
##  [21] "colgroup"    "command"     "data"        "datalist"    "dd"
##  [26] "del"         "details"     "dfn"         "div"         "dl"
##  [31] "dt"          "em"          "embed"       "eventsource" "fieldset"
##  [36] "figcaption"  "figure"      "footer"      "form"        "h1"
##  [41] "h2"          "h3"          "h4"          "h5"          "h6"
##  [46] "head"        "header"      "hgroup"      "hr"          "html"
##  [51] "i"           "iframe"      "img"         "input"       "ins"
##  [56] "kbd"         "keygen"      "label"       "legend"      "li"
##  [61] "link"        "mark"        "map"         "menu"        "meta"
##  [66] "meter"       "nav"         "noscript"    "object"      "ol"
##  [71] "optgroup"    "option"      "output"      "p"           "param"
##  [76] "pre"         "progress"    "q"           "ruby"        "rp"
##  [81] "rt"          "s"           "samp"        "script"      "section"
##  [86] "select"      "small"       "source"      "span"        "strong"
##  [91] "style"       "sub"         "summary"     "sup"         "table"
##  [96] "tbody"       "td"          "textarea"    "tfoot"       "th"
## [101] "thead"       "time"        "title"       "tr"          "track"
## [106] "u"           "ul"          "var"         "video"       "wbr"

To create a tag, run an element of tags as a function. To create a div tag, you can run:

tags$div()
## <div></div> 

You can call some of the most popular tags with helper functions (that wrap the appropriate tags functions). For example, the helper function code calls the tags$code and creates text formatted as computer code. The helper functions that can call their equivalent tags without using the tag syntex (tags$) are: a, br, code, div, em, h1, h2, h3, h4, h5, h6, hr, img, p, pre, span, and strong.

The names of other tags functions conflict with the names of native R functions, so you will need to call them with the tags$ syntax. For example, to embed a plug-in or third party application call it with tags$embed.

Every tag function will treat its arguments in a special way: it will treat named arguments as HTML attributes and unnamed arguments as HTML children.

Attributes

A tag function will use each named argument to add an HTML attribute to the tag. The argument name becomes the attribute name, and the argument value becomes the attribute value. So for example, if you want to create a div with a class attribute, use:

tags$div(class = "header")
## <div class="header"></div>

To add an attribute without a value, set the attribute to NA:

tags$div(class = "header", checked = NA)
## <div class="header" checked></div>

Children

Each tag function will add unnamed arguments to your tag as HTML children. This addition lets you nest tags inside of each other (just as in HTML).

tags$div(class = "header", checked = NA,
  tags$p("Ready to take the Shiny tutorial? If so"),
  tags$a(href = "shiny.rstudio.com/tutorial", "Click Here!")
)
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
## </div> 

withTags

You can save typing by wrapping your HTML objects with withTags. withTags is similar to R’s regular with function. R will lookup each tag function mentioned inside withTags in the tags object, even if you do not specify tags$.

withTags({
  div(class="header", checked=NA,
    p("Ready to take the Shiny tutorial? If so"),
    a(href="shiny.rstudio.com/tutorial", "Click Here!")
  )
})
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
## </div> 

Once you have a complete tag, you can add it directly to your app’s shinyUI function. For example, you could add the tag above to the ui.R file of 01-hello:

library(shiny)

# Define UI for application that draws a histogram
shinyUI(fluidPage(

  # Application title
  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),

      # adding the new div tag to the sidebar            
      tags$div(class="header", checked=NA,
               tags$p("Ready to take the Shiny tutorial? If so"),
               tags$a(href="shiny.rstudio.com/tutorial", "Click Here!")
      )
    ),

    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
))

Your updated app will contain the new HTML element.

01_hello

Conditional attributes and children

If you set an argument of a tag function to NULL, the argument will not appear in the HTML output. NULL gives you a way to build attributes and children that will appear only under certain conditions.

tags$div(class = "header", id = NULL,
	NULL,
	"line 2"
)
## <div class="header">line 2</div> 


tags$div(class = "header", id = if (FALSE) 100,
	if (FALSE) "line 1",
	"line 2"
)
## <div class="header">line 2</div> 

Lists

You can pass a list of children to a tag with R’s list function. The tag function will add each element of the list as a child of the tag.

tags$div(class="header", checked=NA,
  list(
    tags$p("Ready to take the Shiny tutorial? If so"),
    tags$a(href="shiny.rstudio.com/tutorial", "Click Here!"),
    "Thank you"
  )
)
## <div class="header" checked>
##   <p>Ready to take the Shiny tutorial? If so</p>
##   <a href="shiny.rstudio.com/tutorial">Click Here!</a>
##   Thank you
## </div> 

Raw HTML

You cannot put raw HTML directly into a tag object or into shinyUI. Shiny will treat raw HTML as a character string, adding HTML as text to your UI document.

tags$div(
  "<strong>Raw HTML!</strong>"
)
## <div>&lt;strong&gt;Raw HTML!&lt;/strong&gt;</div> 

To add raw HTML, use the HTML function. HTML takes a character string and returns it as HTML (a special class of object in Shiny).

tags$div(
  HTML("<strong>Raw HTML!</strong>")
)
## <div><strong>Raw HTML!</strong></div> 

Shiny will assume that the code you pass to HTML is correctly written HTML. Be sure to double check it.

Warning

It is a bad idea to pass an input object to HTML:

tags$div(
  HTML(input$text)
)

This allows the user to add their own HTML to your app, which creates a security vulnerability. What you user enters could be added to the web document or seen by other users, which might break the app. In the worse case scenario, a user may try to deploy malicious Cross Site Scripting (XSS), an undesirable security vulnerability.

Recap

You can use HTML to customize your Shiny apps. Every Shiny app is built on an HTML document that creates the apps’ user interface. Usually, Shiny developers create this document by giving shinyUI R functions that build HTML output. However, you can supply HTML output directly with Shiny’s tags object.



We love it when R users help each other, but RStudio does not monitor or answer the comments in this thread. If you'd like to get specific help, we recommend the Shiny Discussion Forum for in depth discussion of Shiny related questions and How to get help for a list of the best ways to get help with R code.

comments powered by Disqus