rshinynavbarbslib

How to avoid overlaying body content when using a fixed navigation bar?


The bslib::page_navbar function has a position parameter that allows us to keep the navigation bar visible when scrolling down (position="fixed-top"). However, as the documentation points out:

Note that using "fixed-top" or "fixed-bottom" will cause the navbar to overlay your body content, unless you add padding, e.g.: tags$style(type="text/css", "body {padding-top: 70px;}")

I am trying to do this, but with limited success. Here is what I tried:

library(bslib)
library(shiny)
library(lorem) # for mock data
ui <- bslib::page_navbar(
    theme=bslib::bs_theme(version=5), 
    title="Fixed Navbar Demo",
    position="fixed-top",

    # does not work:
    # shiny::tags$style(type="text/css", "body {padding-top: 170px;}"), 

    # this works, but I may not have a h2 tag at the top:
    shiny::tags$style(type="text/css", "h2 {padding-top: 170px;}"), 

    bslib::nav_panel(
        "Menu Entry",
        shiny::h2("Content"),
        lorem::ipsum(paragraphs=10)
    )
)
server <- function(input, output, session) {}
shiny::shinyApp(ui, server)

Searching on stackoverflow, I found hints to bslib::bs_add_rules and "affix" but I could not get it working. How to do this?


Solution

  • The issue is that since no padding parameter is passed to page_navbar, this defaults to 0px for body and this overwrites the body {padding-top: 170px;}. Hence, you could force the usage of your value by setting

    body {
      padding-top: 170px !important;
    }
    

    (Unrelated here, but please wrap styles inside the header argument of page_navbar: header = tags$head(tags$style(type="text/css", "body {padding-top: 170px !important;}")), then you avoid a warning).

    However, overwriting defaults by !important is usually not the best way to go. A better possibility might be to use the padding parameter of page_navbar, but then you may need to also define the other values (e.g. padding-bottom). Notice that they default to bslib-spacer * 1.5 with bslib-spacer = 1rem. So you could also use something like this:

    library(bslib)
    library(shiny)
    library(lorem) # for mock data
    
    ui <- bslib::page_navbar(
      theme = bslib::bs_theme(version = 5), 
      title = "Fixed Navbar Demo",
      position = "fixed-top",
      
      padding = c(170, "1.5rem", "1.5rem", "1.5rem"),
      
      bslib::nav_panel(
        "Menu Entry",
        shiny::h2("Content"),
        lorem::ipsum(paragraphs=10)
      )
    )
    
    shinyApp(ui, \(...){})