Shiny Get Started

A quick overview of Shiny app structure, layout options, input functions, and output functions.

Published

November 9, 2026

Main Format

To create and run a Shiny App in Positron:

  1. Create a new R script (e.g., app.R) or open an existing Shiny app file.
  2. Positron automatically detects Shiny applications and displays a “Run App” button (or play icon) in the editor toolbar, or you can run shinyApp(ui, server) in the console.

After library calls, there are three main components to every Shiny app:

  1. ui: user interface, the part that the user sees and interacts with

  2. server the R-backend, the part that processes data, performs calculations, and generates outputs

  3. shinyApp() function to connect them

library(shiny)

# define how the page looks & interacts with the user
ui <- fluidPage() # standard basic template 

# define server logic
server <- function(input,output){
  # R-code for data-wrangling & plotting
}

# Run the application 
shinyApp(ui = ui, server = server)

Which Tool? Question → Tool Cheat Sheet

Before writing any code, look at your data and your question, then pick the tools that fit. A good app uses only a few of them, and each one has a reason to be there.

If your data / question is… reach for these inputs… …and these outputs
change over time (a date or year column) dateRangeInput(), or sliderInput() with dates or years line plot (geom_line())
comparing a few categories selectInput(), checkboxGroupInput() bar chart or lollipop (geom_col(), geom_segment() + geom_point())
comparing many categories (10+) selectInput(multiple = TRUE) sorted bar chart, or a DT table
places (counties, states, lat/lon) click on the map (plotOutput(click = ...)) sf map with geom_sf(), or leaflet
relationship between two numbers selectInput() to choose x and y; plot click / brush scatterplot; plotly for hover
the distribution of one number sliderInput() for bins, checkboxInput() for a density curve histogram, boxplot
“what does the data actually look like?” filters in the sidebar DT table (DTOutput())
one number that matters (none needed) value_box()
several views of the same data the same inputs shared by all views tabs (navset_card_tab()), all reading one shared reactive()
something random, slow, or “on demand” actionButton() eventReactive()
something to remember between clicks actionButton() or a plot click reactiveVal()
users want to keep the result downloadButton() downloadHandler()

Three questions to ask yourself:

  1. What type is the variable? Dates call for date inputs and line plots, categories for selects and bars, numbers for sliders and scatterplots, and places for maps.
  2. How many values does it have? With 3 categories, use checkboxes. With 80, use a searchable select or a table.
  3. What should the user do? To look, use a plot. To look something up, use a table. To compare, use the same chart filtered differently. To explore, add click, brush or hover.

Below are the functions & packages used to build the user interface (layout), collect input from the user (inputs), and display results (outputs).

User Interface Layout Options

Functions marked ★ appear in the class examples (app-basic1.R to app-basic10.R).

1. Start with a page

Every ui is wrapped in exactly one page function. Pick one:

  • ★ page_fluid() (bslib): a simple page that resizes to fit the screen. The easiest place to start.
  • ★ page_fillable() (bslib): a page whose contents stretch to fill the browser window. Good for cards and dashboards.
  • page_sidebar() (bslib): a page with a built-in sidebar for inputs, plus a main area for outputs.
  • page_navbar() (bslib): a page with a navigation bar across the top, so you can build a multi-page app with nav_panel().
  • fluidPage() (base Shiny): the older version of page_fluid(). You’ll see it in many online examples.

2. Divide the page into regions

  • Sidebar + main panel (the classic “inputs on the left, plot on the right”):
    • ★ sidebarLayout(sidebarPanel(...), mainPanel(...)) (base Shiny)
    • layout_sidebar(sidebar(...), ...) (bslib), the modern equivalent
  • Columns / grid:
    • ★ layout_column_wrap(width = 1/2, ...) (bslib): equal-width columns that wrap onto new rows automatically
    • layout_columns(col_widths = c(4, 8), ...) (bslib): columns of chosen widths on a 12-column grid
    • fluidRow(column(4, ...), column(8, ...)) (base Shiny): the older 12-column grid

3. Put content in boxes

  • ★ card(): a bordered box that holds inputs, text or outputs
    • ★ card_header(): a title bar at the top of a card
    • ★ card_body(): the main content area of a card (useful for setting height)
    • card_footer(): a bar at the bottom of a card
  • value_box(): a big-number “KPI” box (e.g. “Penguins shown: 152”). Pair it with textOutput().

4. Organize content into tabs

  • ★ navset_card_tab(nav_panel("Tab 1", ...), nav_panel("Tab 2", ...)) (bslib): tabs inside a card
  • navset_tab() / navset_pill() (bslib): tabs or pills without a card around them
  • tabsetPanel(tabPanel(...), tabPanel(...)) (base Shiny): the older way to make tabs
  • page_navbar() (see above): tabs for the whole page instead of one section

5. Add titles & text

  • ★ titlePanel(): the title at the top of the app
  • ★ headings: h1() to h6()
  • ★ paragraphs and line breaks: p(), br()
  • ★ text styles: strong() (bold), em() (italic), code() (code font)
  • ★ styled groups: div(..., style = "color:blue") for blocks of text, span() for words inside a paragraph
  • ★ raw HTML: tags$a(href = ...) for links, tags$img(src = ...) for images
  • ★ math: withMathJax() plus \\( ... \\) for LaTeX (see app-basic3.R)

6. Change the look (themes)

  • bs_theme() (bslib): set colors and fonts, or pick a Bootswatch theme, e.g. page_fluid(theme = bs_theme(bootswatch = "minty"), ...)
  • shinythemes package: older one-line Bootswatch themes, e.g. fluidPage(theme = shinytheme("flatly"), ...)
  • bslib dashboards guide

7. Complete dashboard frameworks (beyond this class)

These replace the page functions above with their own system:

  • shinydashboard: a classic fixed dashboard layout (header, sidebar menu, body)
  • bs4Dash: a more modern version of shinydashboard, with more widgets
  • shiny.fluent: Microsoft’s Fluent UI design system for Shiny

Input Functions

Inputs go in the ui. Each one has an ID (its first argument), and the server reads its current value with input$ID. For example, sliderInput("x", ...) is read as input$x.

Option Function Description Key Use Case
1. Slider sliderInput() A slider bar for selecting a single numeric value or a range of values. Tuning Parameters: Setting a number of clusters in k-means, or choosing a confidence interval.
2. Select Box selectInput() A drop-down menu that lets the user choose one or multiple options from a predefined list. Choosing Variables: Selecting which column in a dataset to plot on the X-axis.
3. Action Button actionButton() or actionLink() A simple clickable button that generates an event when pressed. Triggering Events: Refreshing a dataset, running a time-consuming calculation, or downloading a report.
4. Checkbox checkboxInput() A single box that can be either checked (TRUE) or unchecked (FALSE). Toggling Features: Showing or hiding a data trend line on a plot.
5. Checkbox Group checkboxGroupInput() A group of checkboxes allowing the user to select multiple options from a list. Filtering Data: Selecting which categories (e.g., product lines) to include in an analysis.
6. Radio Buttons radioButtons() A set of circular buttons where the user can choose only one option from the group. Selecting Modes: Choosing between “Raw Counts” or “Per Capita” for a visualization.
7. Numeric Input numericInput() A text box specifically for entering numeric values, with optional minimum, maximum, and step controls. Exact Entry: Allowing the user to enter a precise value, like a sample size.
8. Date Input dateInput() or dateRangeInput() A pop-up calendar widget for selecting a single date or a date range. Time-Series Filtering: Defining the start and end dates for data displayed on a chart.
9. Text Input textInput() A simple text box for users to type in a short string of text. Search/Labeling: Entering a search term to filter results, or providing a plot title.
10. File Upload fileInput() A button that opens the user’s file explorer, allowing them to upload a file (e.g., CSV, Excel) to the app. Custom Data: Allowing users to analyze their own data files within the application.

Output Functions

Outputs always come in pairs:

  • an *Output() function in the ui, which says where the result appears
  • a matching render*() function in the server, which says what to draw

They’re connected by an ID:

# ui
plotOutput("myplot")

# server
output$myplot <- renderPlot({
  ggplot(df, aes(x = x_val, y = y_val)) + geom_line()
})

Used in the class examples

Output ui function server function Description Used in
1. Plot plotOutput() renderPlot() A static plot, usually a ggplot. app-basic1.R to app-basic3.R
2. Table tableOutput() renderTable() A simple HTML table from a data frame or tibble. app-basic2.R, app-basic3.R, app-basic5.R
3. Interactive plot plotlyOutput() renderPlotly() A plotly graph you can zoom, rotate and hover over. Requires library(plotly). app-basic4.R to app-basic10.R
4. Printed R output verbatimTextOutput() renderPrint() Shows output exactly as the R console would print it, in a code-style box. app-basic6.R
5. Dynamic UI uiOutput() renderUI() Builds part of the ui itself on the fly, e.g. showing different inputs depending on a choice. some-app.R

Other good options

Output ui function server function Description Key Use Case
6. Text textOutput() renderText() Plain text that updates, shown inline in a sentence or heading. Live Summaries: “Showing 152 of 344 penguins.” Also works inside a value_box().
7. Interactive table DTOutput() renderDT() A searchable, sortable, paginated table from the DT package. Browsing Data: Letting users explore the filtered rows themselves.
8. Interactive ggplot girafeOutput() renderGirafe() A ggplot with hover tooltips and clickable points, from the ggiraph package. Keep ggplot syntax: Interactivity without switching to plot_ly().
9. Map leafletOutput() renderLeaflet() An interactive, zoomable map from the leaflet package. Spatial Data: Plotting locations or regions (see notes.R for links).
10. Image imageOutput() renderImage() Displays an image file (png, jpg), including one generated in the server. Pictures/Animations: Showing a saved figure or a gganimate gif.
11. Download downloadButton() downloadHandler() A button that lets the user download a file, such as the filtered data as a csv. Exporting Results: “Download the data you’re looking at.”