Move Shiny navlistPanel to the sidebar

Using the navlistPanel function in the Shiny package, I found that too much (for my purposes) screen real estate was taken up by having the navigation list show in the main panel area to the right of the sidebar, directly lumped with the tab panels referenced in the navlistPanel call. So I looked for a way to make it more indirect. I wanted the list to appear as a wellPanel in the sidebar along with my other sidebar inputs.

There may be better ways, but below is what I came up with for anyone who is interested.

One of the benefits of the navigation list is for when there are a lot of elements and a tabsetPanel might appear cluttered. So let’s say we have ten tab panels. In my sidebarPanel call, I include the following:

navlistPanel(
    "Heading 1",
    tabPanel("tab panel 1", value="tp1"),
    tabPanel("tab panel 1", value="tp2"),
    tabPanel("tab panel 1",value="tp3"),
    tabPanel("tab panel 1", value="tp4"),
    tabPanel("tab panel 1", value="tp5"),
    "Heading 2",
    tabPanel("tab panel 1", value="tp6"),
    tabPanel("tab panel 1", value="tp7"),
    tabPanel("tab panel 1", value="tp8"),
    "Heading 3",
    tabPanel("tab panel 1", value="tp9"),
    tabPanel("tab panel 1", value="tp10"),
    id="nlp",
    widths=c(12,1)
)

Note that the tab panels above have no content, just a tile and a value. There is nothing to display. This is intended because I only want the list in the sidebar. I want content to appear in the main panel. Also, I could not put zero for the tabset content width, but it allows 12 for the navigation list area even with non-zero content width, which seems to suffice for ensuring that the wellPanel generated is the same full width as any others that occur in my sidebar.

Next, in my mainPanel call, I just refer to uiOutput("mpContent"), where mpContent is the reactive expression:

mpContent <- reactive({
    x <- NULL
    if(!is.null(input$nlp)){
        id <- input$nlp
        if(id=="tp1"){
            x <- tabPanel("The real tabPanel1", 
            #[All content here. divs, plots, tables, text, etc.]
            )
        } else if(id=="tp2") {
            x <- tabPanel("The real tabPanel2",
            #[content]
        )
        #...
        #...
        #...
        } else if(id=="tp10") {
            x <- tabPanel("The real tabPanel10",
            #[content]
            )
        }
    }
    x
})

For all I know, something very similar could be done without the use of navigation lists at all. I only thought to make this kind of design in the sidebar after using the navlistPanel function in the main panel area where it was directly tied to the tabset content being displayed (and realizing it wasn’t what I wanted/expected to end up with). So I came to this problem somewhat backwardly. But it looks very nice, and does not seem to introduce any lag or overhead with the extra chain of reactivity involved. There may be better approaches.

This entry was posted by Matt Leonawicz.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: