Page Layout

Lecture 24

Dr. Eric Friedlander

College of Idaho
CSCI 2025 - Winter 2026

Single Page layout

fluidPage()

  • The foundation of most Shiny app layouts.
  • Creates a “fluid” page that automatically adjusts to the browser window size.
  • All UI elements are typically placed inside fluidPage().
ui <- fluidPage(
  "Hello, world!"
)

titlePanel()

  • A common first element in fluidPage() is titlePanel().
  • It creates a large heading, suitable for the app’s title.
  • It also sets the window title of the browser.
ui <- fluidPage(
  titlePanel("My Shiny App")
)

sidebarLayout()

  • A classic two-column layout.
  • Consists of sidebarPanel() (for inputs) and mainPanel() (for outputs).
  • sidebarPanel() is typically placed on the left.
ui <- fluidPage(
  titlePanel("My App"),
  sidebarLayout(
    sidebarPanel(
      # inputs
    ),
    mainPanel(
      # outputs
    )
  )
)

sidebarLayout() positions

  • You can control the position of the sidebar with the position argument.
  • position = "left" (default)
  • position = "right"
sidebarLayout(
  sidebarPanel(
    # inputs
  ),
  mainPanel(
    # outputs
  ),
  position = "right"
)

Multi-row Layouts with fluidRow()

  • For more complex layouts, you can build your own grid.
  • fluidRow() creates a row.
  • column() creates columns within a row.
  • The total width of columns in a row must be 12.
fluidPage(
  fluidRow(
    column(4, 
      "First column"
    ),
    column(8, 
      "Second column"
    )
  ),
  fluidRow(
    column(6, 
      "Third column"
    ),
    column(6, 
      "Fourth column"
    )
  )
)

Nesting Layouts

  • You can nest fluidRow() and column() to create more complex layouts.
  • You can also nest sidebarLayout() inside a column().

tabsetPanel() and navlistPanel()

tabsetPanel()

  • Useful for breaking down a complex app into smaller pieces.
  • Creates a set of tabs.
  • Each tab is created with tabPanel().
mainPanel(
  tabsetPanel(
    tabPanel("Plot", plotOutput("plot")), 
    tabPanel("Summary", verbatimTextOutput("summary")), 
    tabPanel("Table", tableOutput("table"))
  )
)

tabsetPanel() options

  • id: Assign an ID to get the currently selected tab in the server.
  • selected: Set the initially selected tab.
  • type: Change the appearance of the tabs (e.g., “tabs”, “pills”).
  • position: Place tabs on “top”, “bottom”, “left”, or “right”.

Page-level navigation

  • For multi-page apps, navbarPage() is the tool of choice.
  • It creates a navigation bar at the top of the page.
  • It replaces fluidPage() as the top-level UI function.
  • Each tabPanel becomes a “page”.
ui <- navbarPage(
  "My App",
  tabPanel("Page 1", "Content for page 1"),
  tabPanel("Page 2", "Content for page 2")
)

Themes

Getting started with bslib

  • Shiny’s appearance is controlled by the Bootstrap CSS framework.
  • The bslib package makes it easy to customize Bootstrap themes.
  • Use bs_theme() to create a theme and pass it to the theme argument of the page layout function.
ui <- fluidPage(
  theme = bslib::bs_theme(bootswatch = "darkly"),
)

Real-time theming

  • bslib offers an interactive theming tool.
  • Run bs_theme_preview() on your UI to launch a special version of your app where you can tweak theme settings in real-time.
# In the R console
my_ui <- fluidPage()
bslib::bs_theme_preview(my_ui)

Customizing components

  • bs_theme() allows you to customize many aspects of the theme.
    • bg, fg: Background and foreground colors.
    • primary, secondary: Accent colors.
    • base_font, heading_font, code_font: Fonts.
my_theme <- bslib::bs_theme(
  bg = "#202123",
  fg = "#B8BCC2",
  primary = "#EA80FC",
  base_font = bslib::font_google("Inter"),
  "font-size-base" = "1.1rem"
)

You can use Raw HTML and CSS

  • When you need a tag that Shiny doesn’t provide a function for.
  • For minor tweaks to the UI.
  • To integrate with other JavaScript libraries that require a specific HTML structure.
  • But for major style changes, prefer bslib.

Wrap Up

Do Next

  1. Read Chapter 6: Layouts, Themes, and HTML from Mastering Shiny.
  2. There’s NO recitation Gem for this textbook but I recommend creating your own and adding the textbook chapter and these slides.
  3. I reommend working through the Exercises in the textbook.
  4. Move on to Lecture 24!