R Shiny: how to use fontawesome pro version with the icon function?

The trick was, inside the htmlDependency call (in icon() function), to remove package = "shiny" and replace "www/shared/fontawesome" by the absolute path to my FA folder (I also updated the version number).

EDIT: to be more precise, below is the (very slightly) modified icon function:

my_icon = function (name, class = NULL, lib = "font-awesome") {

prefixes <- list(`font-awesome` = "fa", glyphicon = "glyphicon")
  prefix <- prefixes[[lib]]
  if (is.null(prefix)) {
    stop("Unknown font library '", lib, "' specified. Must be one of ", 
         paste0("\"", names(prefixes), "\"", collapse = ", "))
  }
  iconClass <- ""
  if (!is.null(name)) {
    prefix_class <- prefix
    #if (prefix_class == "fa" && name %in% font_awesome_brands) {
    #  prefix_class <- "fab"
    #}
    iconClass <- paste0(prefix_class, " ", prefix, "-", name)
  }
  if (!is.null(class)) 
    iconClass <- paste(iconClass, class)
  iconTag <- tags$i(class = iconClass)
  if (lib == "font-awesome") {
    htmlDependencies(iconTag) <- htmlDependency("font-awesome", 
                                                "5.7.2", "./www/shared/fontawesome/", 
                                                stylesheet = c("css/all.min.css"))
  }
  htmltools::browsable(iconTag)
}

Besides commenting some lines out, the only part I changed is the htmlDependency call. In the original function, it was:

htmlDependency("font-awesome", "5.3.1", "www/shared/fontawesome", package = "shiny",
               stylesheet = c("css/all.min.css", "css/v4-shims.min.css")

The simplest and most reliable way to do this is to:

  1. Put the font-awesome files in a subdirectory of the app, www/fontawesome/

  2. Add the following somewhere to the UI code:

     htmlDependency(
       name = "font-awesome", version = "99.0",
       src = "./www/fontawesome",
       stylesheet = "css/all.min.css"
     )
    

Here's an example app that illustrates:

shinyApp(
  ui = fluidPage(
    "This is a Font-Awesome Pro-only icon: ", icon("acorn"),
    htmlDependency(
      name = "font-awesome", version = "99.0",
      src = "./www/fontawesome", stylesheet = "css/all.min.css"
    )
  ),
  function(input, output, session) { }
)

One potential issue with the other method is that if the ui component contains a call to icon(), and then there is some dynamically-rendered UI (via renderUI() and uiOutput()) which contains a call to my_icon() that uses an icon that's only in Font-Awesome Pro, then that Pro icon will not show up. The method I showed here will not have that problem.

Here's why the other method will have that problem: When the static ui for an application is rendered to HTML, it looks for htmlDependency objects in the ui, and the newest version of an htmlDependency for a given name (in this case "font-awesome") "wins". So if there's just a call to icon() in the code (and no call to my_icon(), or the explicit htmlDependency() in my example), then the htmlDependency for Font-Awesome that wins is the one that comes with Shiny, 5.13.0 as of this writing. The browser will request that version of Font-Awesome.

Later, if a renderUI() inserts a my_icon() with a Pro icon, the HTML will be sent to the browser along with an htmlDependency object for Font-Awesome Pro. However, at that point, the browser already has loaded Font-Awesome, and it will not know to load this newer version of it -- Shiny currently is not able to replace the already-loaded version of Font-Awesome with a newer one.

Adding the custom htmlDependency to the static ui object makes it so it can be resolved at initial page render time, and the browser knows to load the newer version from the start. The version I used, 99.0, ensures that this custom version will "win" over any other version of a Font-Awesome htmlDependency.