Custom icons in R shiny

Hans Weda
7 min readDec 18, 2022

When you are working on your data science project it is imperative that your results do not stay in a forgotten pokey corner of your PC. R shiny is a great way to show others your achievements. When building a shiny dashboard you may want to use icons to visually clarify the meaning of buttons or other items in your dashboard.

There are two main libraries with icons you can choose from: Font Awesome and Bootstrap Glyphicons. These libraries provide a rich collections of icons. Still, for your particular project you may want to use a custom icon that contains the logo of a customer. Or you may feel that your message is better conveyed by your own icon. In this blog I will show you how to incorporate your own icons in R Shiny. I will use the images below to create custom icons that illustrate the approach.

Two custom icon-images for demonstration purposes: left icon contains many circles; the right icon contains only few circles. (Images by author).

Custom icon in Shiny actionButtons

As a start, let's consider the default R Shiny application showing the Old Faithful Geyser Data. The folder structure that is used, looks as follows:

.
├── app.R
└── www
├── custom_icon_1.svg
├── custom_icon_2.svg
└── custom_icon.css

The R-script containing the app resides in the main directory. The custom icon-files and css-style file are stored in the default www directory.

The main code of the Shiny app is written in app.R. I have modified the code of the default R Shiny application somewhat by replacing the slider by three action buttons. Each button sets the number of bins used in the histogram to a different value:

  • The first actionButton with id home sets the number of bins to 30. It uses the "house" icon from FontAwesome.
  • The second actionButton with id few sets the number of bins to 10. It uses the custom icon "custom_icon_1.svg". The used image is defined in the R-script itself as background image of the icon. This is done by explicitly defining the style of the icon in the script.
  • The third actionButton with id many sets the number of bins to 60. It uses the custom icon "custom_icon_2.svg". In this case the style of this icon is defined in the supplementary css-file, to be shown later.

The code of the app.R is shown below.

#
# This shiny web application demonstrates the use of custom icons
#

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

# include the css file - necessary for styling the second custom icon
includeCSS(file.path("www", "custom_icon.css")),

# Application title
titlePanel("Old Faithful Geyser Data"),

# Sidebar with a button inputs for number of bins
sidebarLayout(
sidebarPanel(

# actionbutton with an icon from the standard Font Awesome library
actionButton(
inputId = "home",
label = "",
icon = icon("house")
),

# actionButton with a custom icon specified in this R-script
actionButton(
inputId = "few",
label = "",
icon = icon(
name = NULL,
style = "
background: url('custom_icon_1.svg');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
height: 32px;
width: 32px;
display: block;
"
)
),

# actionButton with a custom icon specified in a separate css-file
actionButton(
inputId = "many",
label = "",
icon = icon(
name = NULL,
class = "custom_icon"
)
)
),

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

# Define server logic required to draw a histogram
server <- function(input, output) {

# initiate the number of bins
number.of.bins = reactiveVal(30)

# observe the presses of the actionButtons
observeEvent(input$home, number.of.bins(30))
observeEvent(input$few, number.of.bins(10))
observeEvent(input$many, number.of.bins(60))

output$distPlot <- renderPlot({
# generate bins based on the number.of.bins reactive value
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = number.of.bins())

# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white',
xlab = 'Waiting time to next eruption (in mins)',
main = 'Histogram of waiting times')
})
}

# Run the application
shinyApp(ui = ui, server = server)

For the third actionButton, with id many, the styling is done in a supplementary css-file. This file resides in the www directory and is included by the command includeCSS(file.path("www", "custom_icon.css")), and contains the following code:

/* Styling the custom icon */
.custom_icon {
background: url("custom_icon_2.svg");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
height: 32px;
width: 32px;
display: block;
}

/* Increase font-size of default button */
#home {
font-size: 32px;
line-height: 0;
}

By placing the css-styling in a separate file, the resulting R-code gets more concise and clean, which can be considered an advantage. Additionally one can see that this style-file also modifies the default button, such that it has the same size as the custom buttons, which is visually more appealing.

The resulting Shiny app looks as follows:

Custom icon in Shiny leaflet

Quite similarly one can also add custom icons to leaflets. Leaflets are mainly used to display interactive maps in Shiny dashboards. It is also possibly to add extra buttons to the map, as is explained here. Some of those extra functionality use default buttons, or default icons. In this example we are mainly interested in a custom button with a custom icon. Again, the folder structure is as follows:

.
├── app.R
└── www
├── custom_icon_1.svg
├── custom_icon_2.svg
└── custom_icon.css

The R-code for the Shiny application is shown below. The script launches an app that shows the Bavarian breweries on a map. This datasets is by default contained in the leaflet-package. There are two non-default buttons added to the map by means of the addEasyButton method:

  • The first easyButton bears the title world and zooms out to a view that shows the full world. Quite appropriately it uses the "globe" icon from FontAwesome.
  • The second easyButton bears the title home and zooms in to an area in Bavaria that contains the breweries from the dataset. This button uses a custom icon that is further defined in the css-style file.

Both buttons invoke a JavaScript function that changes the view on the map.

#
# This shiny web application demonstrates the use of custom icons in leaflet
#

library(shiny)
library(leaflet)

# Define UI for application that draws a histogram
ui <- fluidPage(

# include the css file - necessary for styling the second custom icon
includeCSS(file.path("www", "custom_icon.css")),

# Application title
titlePanel("Bavarian breweries"),

# the geographic map
leafletOutput("map")
)

# Define server logic required to draw a histogram
server <- function(input, output) {

output$map <- renderLeaflet({
map <- leaflet(cbind(breweries91@data, breweries91@coords)) %>%
# Add the base map
addTiles(group = "OSM (default)") %>%
# Add markers on the position of the breweries
addMarkers(~longitude, ~latitude, popup=~brewery) %>%
# Add a custom button with a standard icon that shows the whole world
addEasyButton(
easyButton(
icon = "fa-globe",
title = "world",
onClick = JS("function(btn, map){map.flyTo([0, 0], 1);}")
)
) %>%
# Add a custom button with a custom icon that zooms in to the breweries
addEasyButton(
easyButton(
icon = icon(name=NULL, class="custom_icon"),
title = "home",
onClick = JS("function(btn, map){map.flyToBounds([[49, 10], [50, 11]])}")
)
)

map
})
}

# Run the application
shinyApp(ui = ui, server = server)

The second easyButton, with titlehome, the styling is done in a supplementary css-file. This file resides in the www directory and is included by the command includeCSS(file.path("www", "custom_icon.css")), and contains the following code:

/* Styling the custom icon */
.custom_icon {
background: url("custom_icon_2.svg");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
height: inherit;
width: inherit;
display: block;
}

This styling is slightly different from the previous example. In this case the width and height are inherited from the parent element.

The resulting Shiny app looks as follows:

Concluding words

The code examples above show how to add custom icons to actionButtons in standard Shiny or easyButtons in leaflet-maps in Shiny. The main trick is to add an image as background image to the icon using css-styling. The css-styling can be done in the R-script itself, but is probably best done in a separate css-file. The examples shown here use svg-files which scale nicely. One could however also use other image file-formats such as png-files of jpg-files.

I have made the images used in the examples myself — these are most likely not well suited for real-world applications, and much better icons are provided by one of the default libraries. However, in cases in which you would like to use customer logo's or create non-standard icons yourselves, you can use one of the approaches above to do so.

I am interested in alternative methods for adding custom icons, and in R Shiny tips or tricks in general you’d care to share. Please share your comments and suggestions below!

--

--