Written and maintained by CASRAI Editorial Board
Published
On this page
Who this is for: researchers building a Shiny app in R who need to lay out the user interface (UI) and want to know what fluidPage(), wellPanel() and navlistPanel() each do. After reading you can assemble a page with a sidebar, a left-hand navigation list and a grouped panel, and read which navigation item is active on the server side.
The Shiny user interface is the R code, usually an object named ui, that describes the page a browser shows. fluidPage() is the page container, wellPanel() is a grey inset box for grouping content, and navlistPanel() is a vertical list of links that each open a tab. This page covers the three functions in the current Shiny reference, and shows how they combine with sidebarLayout().
What the Shiny interface is used for in research
Shiny turns an R analysis into an interactive web page. The UI layout functions decide where inputs (sliders, selectors) and outputs (plots, tables) sit. Researchers use this to share a model, a data explorer or a figure generator with collaborators who do not run R. Once the layout works, an app can be published with shinyapps.io, and its outputs are built with functions such as those compared in renderTable, DT and renderDataTable or Plotly in R.
Install or access
Shiny is distributed on CRAN. As of 2026-11-11 the CRAN page lists version 1.14.0, published 2026-06-21, requiring R 3.1.2 or later. Install and load it from the R console, for example from the RStudio console described in How to Use RStudio:
install.packages("shiny")
library(shiny)
Step-by-step: build a page with fluidPage, navlistPanel and wellPanel
- Create a file named
app.Rand start the UI withfluidPage(). - Add a title with
titlePanel()insidefluidPage(). - Add a
navlistPanel()and give it anidso the server can see the active item. - Inside it, add plain text strings as headers and
tabPanel()elements as items. - Put a
sidebarLayout()inside one tab for an input-and-output page, and awellPanel()inside another to group content. - Write the server function and finish with
shinyApp(ui, server), then run the app (in RStudio, the Run App button on the editor).
library(shiny)
ui <- fluidPage(
titlePanel("Shiny interface demo"),
navlistPanel(
id = "section",
widths = c(3, 9),
"Explore",
tabPanel("Histogram",
sidebarLayout(
sidebarPanel(
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500)
),
mainPanel(plotOutput("distPlot"))
)
),
"About",
tabPanel("Notes",
wellPanel(
p("A wellPanel groups related content in an inset grey box."),
textOutput("current")
)
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$obs))
})
output$current <- renderText({
paste("Active item:", input$section)
})
}
shinyApp(ui, server)
The slider and histogram follow the reference’s “Hello Shiny!” sidebar example. The navlistPanel id argument makes input$section available on the server, which here is echoed in the Notes tab.
fluidPage()
Signature in the current reference: fluidPage(..., title = NULL, theme = NULL, lang = NULL). It creates a page with rows and columns on a 12-unit grid; the layout scales to the width of the browser. title sets the browser window title. theme accepts NULL (the default Bootstrap 3 styling), a bslib::bs_theme() object or a custom stylesheet string. Rows are made with fluidRow() and columns with column(width, ...); for example fluidRow(column(width = 4), column(width = 3, offset = 2)). sidebarLayout() is the higher-level alternative to building rows and columns by hand.
sidebarLayout(), sidebarPanel() and mainPanel()
sidebarLayout(sidebarPanel, mainPanel, position = c("left", "right"), fluid = TRUE). sidebarPanel(..., width = 4) and mainPanel(..., width = 8) use the same 12-unit grid, and their total width must be 12 or less.
wellPanel()
wellPanel(...) creates a panel with a slightly inset border and a grey background. It corresponds to the Bootstrap well class. Use it to visually group a set of related inputs or text.
navlistPanel()
Signature: navlistPanel(..., id = NULL, selected = NULL, header = NULL, footer = NULL, well = TRUE, fluid = TRUE, widths = c(4, 8)). It shows a list of links on the left; each link opens a tabPanel() on the right. Plain text elements in the list act as headers. Separators are not supported (since Shiny 0.11). If id is set, input$<id> returns the active item (the tab’s value). With well = TRUE the list sits in a grey, rounded box; widths sets the relative width of the list and the content area.
Output and how to read it
Running the example opens a page with a title, a grey navigation list on the left (headers “Explore” and “About”, items “Histogram” and “Notes”) and the selected tab’s content on the right. In the Histogram tab, moving the slider redraws the histogram with a new number of random normal draws. In the Notes tab the text shows the value of input$section, the item last chosen.
Troubleshooting
- Sidebar and main panel do not fit: the combined
widthvalues must be 12 or less. input$sectionis NULL:navlistPanel()only reports the active item whenidis set.- Divider lines in the list do not appear: separators have not been supported since Shiny 0.11; use text headers instead.
- Layout looks like the default styling:
theme = NULLinfluidPage()gives stock Bootstrap 3; pass abslib::bs_theme()object to change it.
Free alternatives and related layout functions
| Function | What it does (per the Shiny reference) |
|---|---|
fluidPage() |
Page container with rows and columns on a 12-unit grid that scales to the browser width |
sidebarLayout() |
Higher-level layout with a sidebar panel and a main panel, widths totalling 12 or less |
wellPanel() |
Inset grey panel, Bootstrap well class |
navlistPanel() |
Vertical list of links, each opening a tabPanel(); supports id for server-side access |
All four are part of the free, open-source shiny package.
FAQ
What does fluidPage do in Shiny?
fluidPage() creates the page whose rows and columns use a 12-unit grid and scale to the browser width. Its title, theme and lang arguments set the window title, styling and language.
What is wellPanel in Shiny?
wellPanel() creates a panel with a slightly inset border and a grey background, matching Bootstrap’s well class.
How does navlistPanel work?
navlistPanel() shows a list of links on the left; each opens a tabPanel() on the right. Set id to read the active item as input$<id>.
Sources
- Shiny reference, fluidPage: shiny.posit.co/r/reference/shiny/latest/fluidpage.html (read 2026-11-11)
- Shiny reference, wellPanel: shiny.posit.co/r/reference/shiny/latest/wellpanel.html (read 2026-11-11)
- Shiny reference, navlistPanel: shiny.posit.co/r/reference/shiny/latest/navlistpanel.html (read 2026-11-11)
- Shiny reference, sidebarLayout: shiny.posit.co/r/reference/shiny/latest/sidebarlayout.html (read 2026-11-11)
- CRAN, shiny package: cran.r-project.org/package=shiny (read 2026-11-11)







