Phantom dropdown/option created when adding an external hyperlink to navbarMenu/tabPanel in Shiny

I'm been having a very difficult time adding an external link to a navbarMenu selection in R Shiny. Specifically, when a hyperlink is added to a tabPanel title in navbarMenu, it creates an additional "phantom" tab with no text.

I asked this on stack overflow here

Here is some example code to hopefully demonstrate the problem. Using a hyperlink in the base navbarPage title works as intended (no phantom tab is created), but when the same method is used in a tabPanel or navbarMenu (with tabPanel) it adds a phantom tab.

library(shiny); library(shinythemes)

ui <- bootstrapPage("", 
                    navbarPage(
                      id = "navbar", 
                      theme = shinytheme("yeti"),
                      title = a("Home", href = "https://google.com", style = "color:white;"),  ## page title with hyperlink and browser tab title (works as intended)
                      
                      tabPanel(title = HTML("Panel_1</a></li><li><a href='http://google.com' target='_blank'>test")),  ## tabPanel hyperlink test (adds "phantom" tab)
                      
                      navbarMenu(title = "Test Menu", 
                                 tabPanel(title = a("Open Sales Gsheet", href="http://google.com", target="_blank"))   ## navbarMenu hyperlink test (adds "phantom" option)
                                 )
                      )
                )

server <- function(input, output, session) {
  ## empty server
  }

shinyApp(ui, server)

Here is an image of what that basic app outputs:

(NOTE: I included target='_blank' only because it was included in the stack overflow answers. I would not add this to the hyperlink in my Shiny app).

I've spent a good deal of time trying to dig through the actual navbarMenu list structure to try and manually update the object, but I have limited experience with HTML and/or javascript... so I'm really lost here. Any help would be appreciated!

It's tricky to add custom elements in a shiny navbar page but it can be done with some javascript. The following code should add your link to the dropdown menu in the navbar. Save it as a .js file in your app's base directory then include the script in your ui function.

# navAppend.js in your app's base directory
$(document).ready(function() {
  $(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li><a href="https://google.com" target="_blank">Open Sales Gsheet</a></li>');
});
ui <- tagList(
  tags$head(includeScript("navAppend.js")),
  navbarPage(
    id = "navbar", 
    theme = shinytheme("yeti"),
    title = a("Home", href = "https://google.com", style = "color:white;"),  ## page title with hyperlink and browser tab title (works as intended)
    
    # nav menu the link will be added to
    navbarMenu(title = "Test Menu")
  )
)
1 Like

Thank you! This is great. A couple questions though... My app has multiple navbarMenu dropdowns and only a select number of the options in the navbarMenus should contain hyperlinks - so, some of the options actually use the shiny ui and server.

I figured out how to add additional links in the javascript code you posted, but it looks like ".append" command is adding them in order to the end of the navbarMenu options. Additionally, the javascript code is being applied to all of the navbarMenu dropdowns. Is there a way to specify the navbarMenu that the JS function is being applied to? And is there any way to integrate this with legitimate shiny app pages (linked from the dropdown like normal)? Looking into this a little more, I feel like this is going to be rather difficult, but maybe I'm wrong.

Here is the updated app code I was working with:

# // Add hyperlink to navbarMenu dropdown - UPDATED JS CODE
$(document).ready(function() {
  $(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li><a href="https://google.com">Google</a></li>');
  $(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li><a href="http://www.espn.com/">ESPN</a></li>');
  $(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li><a href="https://www.bbc.com//">BBC</a></li>');
});
ui <- bootstrapPage("", 
                    tags$head(includeScript("navAppend.js")),
                    navbarPage(
                      id = "navbar", 
                      theme = shinytheme("yeti"),
                      windowTitle = "Test App", 
                      title = a("Home", href = "https://google.com", style = "color:white;"),  ## page title with hyperlink and browser tab title (works as intended)
    
                      # nav menu the link will be added to
                      navbarMenu(title = "Test Menu", 
                                 tabPanel(title = "Real Shiny Tab")
                                 ), 
                      
                      navbarMenu(title = "Another Menu", 
                                 tabPanel(title = "Real Shiny Tab")
                                 )
                      )
                    )

server <- function(input, output, session) {
  ## empty server
  }

shinyApp(ui, server)

Thanks for the help!

Hi Luke, sorry for the late response.

So you can add regular shiny tabs to your navbarMenu as you normally would inside the navbarMenu function with tabPanel(title = "A Shiny Tab", ...)

To get the javascript to put different links inside each navbarMenu was a little tricky but I worked out a way:

$(document).ready(function() {
  $(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").each(function(index) {
    const num = index + 1;
    $( this ).addClass("dropdown-menu-" + num);
  });
  
  $(".dropdown-menu-1").append('<li><a href="https://google.com" target="_blank">Google</a></li>');
  $(".dropdown-menu-2").append('<li><a href="https://www.bbc.co.uk" target="_blank">BBC</a></li>');
});

The first bit finds all navbarMenus on your page and assigns them a unique class (dropdown-menu-1, dropdown-menu-2... etc). You can then select these menus individually by this class and append the link you want in each one. So the example above would put a google link in your first menu and a bcc link in the second.

This will work for any number of menus you have, so if you had 5 menus and want to append a link in the 5th you would do $(".dropdown-menu-5").append(...);

Let me know if that works for you!