Shiny Get Started
A quick overview of Shiny app structure, layout options, input functions, and output functions.
Main Format
To create and run a Shiny App in Positron:
- Create a new R script (e.g.,
app.R) or open an existing Shiny app file. - 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:
ui: user interface, the part that the user sees and interacts withserverthe R-backend, the part that processes data, performs calculations, and generates outputsshinyApp()function to connect them
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:
- 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.
- How many values does it have? With 3 categories, use checkboxes. With 80, use a searchable select or a table.
- 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 withnav_panel(). -
fluidPage()(base Shiny): the older version ofpage_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 settingheight) -
card_footer(): a bar at the bottom of a card
- ★
-
value_box(): a big-number “KPI” box (e.g. “Penguins shown: 152”). Pair it withtextOutput().
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()toh6() - ★ 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 (seeapp-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"), ...) -
shinythemespackage: 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 ofshinydashboard, 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.” |