Building custom R Shiny UI

Roshan Santhosh
Analytics Vidhya
Published in
7 min readDec 28, 2019

As part of an ongoing project on building a customized dashboard for the ACLU of Pennsylvania (https://www.aclupa.org), we got to experiment a lot with customizing RShiny UI to meet our design goals. In this post, we discuss some of the techniques we used for customizing the design of the dashboard.

We broadly cover two topics :

  • Adding custom UI elements
  • Customizing Shiny themes

Adding custom UI elements

Shiny comes with a lot of default layout elements like navbarPage, fluidPage, tabsetPanel and so on. However, at times these options might not be enough to recreate the design you have in mind. In such cases, we can resort to using custom HTML code to build our UI.

Our goal for the dashboard was to include a profile page with 3 boxes at the top of the dashboard showcasing 3 key stats.

Design for the Profile page

An initial attempt using a combination of fluidRow and 3 columnelements didn't provide us the results we needed. Moreover, getting the boxes to align properly with the correct spacing between turned out to be a difficult task. Therefore, we ended up using custom HTML instead to build the UI.

boxStyle ='color:black; background-color:#DE4F53; margin: 0 3em 0 3em; border-radius: .5em; height :10vh; color:white; align:center; text-align:center; display: table-cell;
vertical-align: middle'
fluidRow(style = "background-color: #ffffff; height :15vh;",
column(3,div(htmlOutput("box1")), style=boxStyle),
column(3,div(htmlOutput("box2")), style=boxStyle),
column(3,div(htmlOutput("box3")), style=boxStyle))
)

We start off by defining a fluidRow to work as a container for all the 3 boxes. Within the fluidRowelement, we enter 3 column elements each with a defined width.

At this point, it's important to mention that there are 2 different ways of including HTML code in your R shiny app.

  • Using HTML block elements that are predefined in RShiny like div, p, imgetc.
  • Using HTML code written in proper HTML syntax which is then passed as strings to the htmlOutput method.

For our implementation, we make use of both methods. We first use the predefined method to create a div block. This div block is going to serve as the primary box within which we place the text. We then customize the div object by defining CSS style parameters in a string and passing it to the style argument of the div method. In our case, all the CSS properties have been defined in the boxStyle variable. These properties ensure that the box has a specific color, curved corners, and responsive height.

After this, we define the text that goes inside each of the boxes. This is done by using the second method.

output$box1 = renderUI({    % Reactive function that retrieves the current data 
df <- data()
style='margin:0;position: absolute;left: 50%;top: 50%;transform:
translate(-50%, -50%);'
a = nrow(df)
b = "Total Cases"

htmlCode= sprintf("<p style= %s \> <span style='font-size :23px;
font-weight:bold;'> %s </span></br> %s </p>", style, a, b)
HTML(htmlCode)


})

Within the server function, we define the box1 output element using the renderUI method. We construct an HTML pelement using the current data in order to make it responsive. We also get to enter the CSS style properties within the string itself. We then return the string after passing it through the HTML method. It's important to note that htmlOutput doesn’t accept a string input and hence the string must be passed through the HTML method before passing it on to htmlOutput.

Between the 2 options mentioned above, the second one is the more flexible option and can essentially do everything that can be achieved using the first option.

Another instance of using custom HTML is the info panel that we added to this page. This specific panel consists of p, imgandtable HTML elements added using the second method. Building such a panel, especially the table element with its custom fonts and text alignment, would be a nearly impossible task using default RShiny layout options alone.

Customizing Shiny Themes

Shiny comes with a lot of options for themes (https://rstudio.github.io/shinythemes)/ which can be easily implemented by using the shinythemes package. Though there are a lot of options, at times we might need to change these themes to reflect the overall design of our app. In our case, since we were building an app for ACLU, we wanted to stick with the ACLU colors throughout the app.

We started off by building our app using the Flatly theme. This theme has its own default color scheme which is used throughout the app.

To start modifying the theme, we need to first get the CSS file for this theme. We can get the themes for all Shiny themes at Bootswatch (https://bootswatch.com/flatly) by downloading the bootstrap.min.css file.

The CSS file should look something like this. What we see here are the properties set for all the different types of elements in our app and for their different states.

To use this CSS file, create a folder called www within your shiny project and place the file there.

After this, in your UI function, set the theme argument to point to this file. At this stage, we have established a link between our app and the CSS file and any changes we make to the CSS file would reflect on the app’s design.

The key step in making changes to UI is to identify which CSS property defines the design of the UI element you are interested in. For this, the best approach is to open the app in a browser and inspect the CSS code. In Chrome, this can be done by using the Developer Tools option.

We select the UI element that we want to modify and can see the design CSS properties under the Stylestab. In this case, we are interested in the navigation bar headers. We can see that the background-color property of the navigation bar headers is set under .nav>li>a and has a value of #0055A8. It also tells us that this code is at line 2922 in the bootstrap.css file.

So to modify the background-color property, we go back to the CSS file and change the background-color to red and reload the app.

We can now see that the navigation bar elements now have their background-color set as red. You can also notice that under the Styles tab, the .nav>li>a selector now shows the updated background-color property.

Finally, by making changes to quite a few properties, we could modify the default flatly theme to match our desired color theme.

Before and after CSS file modification

Notes

  • Chrome doesn't always load the latest CSS file and hence recent changes might not be reflected in the app when you open it in the browser. To confirm if the browser is using the latest version, find the CSS file under the Sources tab of Developer tools and check if recent changes are reflected in the file shown there.
  • Though we mostly modified color properties for our app, using this approach, all sorts of CSS properties like text color, fonts, etc can be modified.
  • To view the behavior of a UI element under different states, use the Toggle Element state option to forcefully set the state of an element to hover, active, focus etc.
Setting different state for UI elements
  • In certain cases, a CSS property needs to be set for a particular element alone and not all instances of the same type. In such cases, we can assign these UI elements to a specific class and then define properties specific to the class. In the given example, we define a custom class called tabsetClass and define properties specifically for it.
Setting CSS properties for a custom class

--

--

Roshan Santhosh
Analytics Vidhya

Interested in topics of NLP, CV and GenAI | Data Scientist @ Meta | MS Data Science ’20 UPenn