18  HTML

Warning

The contents for section are under development. Thank you for your patience.

In this chapter, we explore how to enhance our app UI by integrating custom HyperText Markup Language (HTML) in our app-package. Web content is made of HTML elements (headings, paragraphs, links, images, and multimedia elements). HTML elements are represented as tags1, which are nested within each other to build a complete document (or web application). As you can imagine, even a basic understanding of HTML can be valuable for designing the user interface of a Shiny applications.

18.1 Shiny and HTML

While Shiny provides a high-level interface for building web applications using R, incorporating raw HTML allows for finer control and customization of the app’s appearance and layout. Knowing a little HTML gives us the ability to create polished and professional UIs. Some basic HTML skills also enables us to include additional content types and structures–beyond what is natively supported by Shiny’s UI functions–allowing for greater flexibility and creativity in our app design.

18.2 htmltools

The htmltools package facilitates the creation of HTML elements and documents within R. htmltools provides functions to create tags, manage dependencies, and render HTML documents. htmltools is imported when we install and load shiny,2, so the tags object is automatically available.

We’re already using HTML tags in our movies_ui() function to reference the original source of the movies data and application:

show/hide
tags$blockquote(
  tags$em(
    tags$p(
      "The data for this application comes from the ",
      tags$a("Building web applications with Shiny",
        href = "https://rstudio-education.github.io/shiny-course/"
      ),
      "tutorial"
    )
  )
)

HTML tags are the building blocks of HTML documents. They are enclosed in angle brackets (<tag>) and define the structure and content of the web page. htmltools is particularly useful in Shiny app-packages because it allows you to build complex HTML structures programmatically. If we view the output from the block quote above, we see the raw HTML:

<blockquote>
  <em>
    <p>
      The data for this application comes from the
      <a href="https://rstudio-education.github.io/shiny-course/">Building web applications with Shiny</a>
      tutorial
    </p>
  </em>
</blockquote>

htmltools$tags() allows us to create HTML elements directly within our R code. The sections below cover some of the common HTML tags used by htmltools::tags in Shiny applications.

18.2.1 Headings

Headings are used to define the hierarchy and structure of content on a web page. They range from <h1> (the most important heading) to <h6> (the least important heading):

tags$h1("Level 1")
<h1>Level 1</h1>

Level 1

tags$h2("Level 2")
<h2>Level 2</h2>

Level 2

tags$h3("Level 3")
<h3>Level 3</h3>

Level 3

18.2.5 Paragraphs

Paragraphs are used to define blocks of text. They are enclosed within <p> tags.

tags$p("Block of text.")
<p>Block of text.</p>

Block of text.

18.2.6 Divisions and Spans

<div> and <span> are generic containers used to group and style content. <div> is a block-level element used to group larger sections of content:

tags$div(
  tags$p("Paragraph in a div.")
)
<div>
  <p>Paragraph in a div.</p>
</div>

Paragraph in a div.

<span> is an inline element used to style smaller parts of the text:

tags$p("Some ",
  tags$span(
    style = "color: red;", 
  "red"), " words."
  )
<p>
  Some 
  <span style="color: red;">red</span>
   words.
</p>

Some red words.

18.2.7 Text Styling

HTML tags can be used to create many of the same styles we use in markdown. For example, we can format text as code using the <code> and <pre> tags.

<code> is better for highlighting a small piece of code within a paragraph of text.

tags$code("library(shiny)")
<code>library(shiny)</code>
library(shiny)

<pre> is better for multiline code because it preserves both spaces and line breaks:

tags$pre("for(i in 1:5) {
    print(paste0('#', i))
  }")
<pre>for(i in 1:5) {
    print(paste0('#', i))
  }</pre>
for(i in 1:5) {
    print(paste0('#', i))
  }

We can also combine <pre> and <code>:

tags$pre(
  tags$code("
    for(i in 1:5) {
      print(paste0('#', i))
    }")
  )
<pre>
  <code>for(i in 1:5) {
      print(paste0('#', i))
    }</code>
</pre>
for(i in 1:5) {
    print(paste0('#', i))
}

We can also specify bold (<strong>) and italic (<em>).

tags$strong("bold")
<strong>bold</strong>
bold
tags$em("italic")
<em>italic</em>
italic

18.2.9 Images

The <img> tag is used to embed images in an HTML document. The src attribute specifies the path to the image file, and the alt attribute provides alternative text for the image:

tags$img(src = "logo.png")
<img src="logo.png" />

align, width, and height control the size and position of the image.

18.3 Custom inputs

The HTML output generated by htmltools plays well with Shiny, so we could use it to custom inputs.3 For example, in this branch we have a simple buttonApp() application that collects a name text input and displays a greeting.

show/hide custom button inputs
tags$form(
  tags$label("Enter your name:"),
  tags$input(
    type = "text",
    id = ns("name_input"),
    name = "name"
  ),
  tags$input(
    type = "submit",
    id = ns("button_click"),
    value = "Click me!"
  )
)

Custom submit button

As we can see, mod_cust_button_ui() uses the tags$form() from htmltools to create a custom text input area and submit button in the sidebar. The mod_cust_button_server() module function returns the text input as a reactive (txt).

show/hide custom input ui/server functions
buttonUI <- function() {
  tagList(
    bslib::page_fillable(
      bslib::layout_sidebar(
        sidebar = bslib::sidebar(
          mod_cust_button_ui(id = "click")
        )
      )
    )
  )
}
buttonServer <- function(input, output, session) {
  
  txt <- mod_cust_button_server(id = "click")
  
}
1
Text input collected in tags$input() (in UI)
2
Text returned as reactive txt input (in server)

To render the output, we pass txt as an input to mod_greeting_server() and display the output using the mod_greeting_ui():

show/hide custom output ui/server functions
buttonUI <- function() {
  tagList(
    bslib::page_fillable(
      bslib::layout_sidebar(
        sidebar = bslib::sidebar(
          mod_cust_button_ui(id = "click")
        ),
        bslib::card(
          mod_greeting_ui(id = "greeting")
        )
      )
    )
  )
}
buttonServer <- function(input, output, session) {
  
  txt <- mod_cust_button_server(id = "click")
  mod_greeting_server(id = "greeting", txt = txt)
  
}
1
Text input collected in tags$input() (in UI)
2
Text returned as reactive txt input (in server)
3
Text passed to renderText() (in server)
4
txt() rendered in textOutput() (in UI)

buttonApp

To aid us in understanding how the cutom text input works with submit button inside the modules, we’ll also add a card with verbatimTextOutput() and set it to display the output of reactiveValuesToList():

show/hide reactive value display functions
buttonUI <- function() {
  tagList(
    # UI code ...
      bslib::card(
        verbatimTextOutput(outputId = "vals")
      )
    )
}
buttonServer <- function(input, output, session) {
  # server code ...
  output$vals <- renderPrint({
    x <- reactiveValuesToList(x = input, all.names = TRUE)
    print(x)
  })
  
}

Now buttonApp() will display the value of txt() input as $`click-name_input`.

buttonApp with reactiveValuesToList()

When we enter a value in the text area, we see nothing is printed in the output from reactiveValuesToList() or textOutput() until we click the submit button, then the reactive values update with the value and the name is printed in the card:

(a) buttonApp + name input
(b) buttonApp + name input + submit
Figure 18.1: Text updates in buttonApp()

When we change the value to a different name, the UI doesn’t change until we click the submit button again:

(a) New name input
(b) New name input + submit
Figure 18.2: Text updates in buttonApp()

18.4 htmlwidgets

The htmlwidgets package is another powerful tool that allows you to create interactive JavaScript data visualizations and embed them in your Shiny applications and R Markdown documents. htmlwidgets provides a framework for binding R to JavaScript libraries, enabling you to create interactive plots, maps, and other data visualizations that can be embedded in your Shiny apps.

Key features of htmlwidgets include:

  • Interactivity: Create interactive visualizations that respond to user inputs.

  • Embeddability: Embed widgets in Shiny applications, R Markdown documents, and static HTML pages.

  • Customizability: Customize the appearance and behavior of widgets using both R and JavaScript.


  1. w3schools has a great (free) intro to HTML course.↩︎

  2. htmltools is listed under the Imports field of Shiny’s DESCRIPTION file.↩︎

  3. Defining a custom Shiny HTML input covered in the Shiny documentation.↩︎