15.5 Building Dashboards in R
R provides a complete ecosystem for building dashboards, from simple static displays to fully interactive web applications. The tools build on each other in a progression that mirrors the complexity of the dashboard being built.
15.5.1 The R Dashboard Landscape
Quarto is the modern standard for combining code, output, and narrative in R — as introduced in Chapter 3. Quarto includes a native dashboard format (format: dashboard) that uses the same Markdown syntax you already know: headings define rows and columns, code chunks produce charts, and the result is a self-contained HTML file. Quarto dashboards support R, Python, and Julia, making them a strong choice for teams working across languages. See the Quarto appendix for details on dashboard syntax.
flexdashboard is an R package that predates Quarto’s dashboard format but remains widely used (Iannone et al. 2024). Built on R Markdown (Quarto’s predecessor), flexdashboard uses the same heading-based layout approach and adds dashboard-specific components like value boxes and gauges. The output is a self-contained HTML file that can be opened in any browser, emailed as an attachment, or hosted on a web server. No special infrastructure is required.
Shiny adds server-side interactivity (Chang et al. 2024). While Quarto dashboards and flexdashboard produce static HTML (the data is fixed at render time), Shiny enables reactive dashboards where user inputs (dropdown menus, sliders, date pickers) dynamically filter and update the display. Shiny dashboards require a running R process — either locally or on a server like shinyapps.io — which adds complexity but enables real-time data connections and interactive exploration.
For this book, Chapter 16 builds a dashboard using flexdashboard because of its mature component library (value boxes, gauges) and extensive documentation. The design principles and layout concepts transfer directly to Quarto dashboards — the underlying logic is the same, and students comfortable with flexdashboard can adopt Quarto dashboards with minimal adjustment.
15.5.2 flexdashboard Basics
A flexdashboard document is an R Markdown file with flexdashboard::flex_dashboard as its output format. The layout is defined by Markdown headings: level-2 headings (##) create pages or rows, and level-3 headings (###) create individual panels within a row or column.
Here is the basic structure of a flexdashboard document:
---
title: "Absenteeism Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
---
## Column {data-width=350}
### Average Absence Hours
[value box or chart code here]
### Chronic Absence Rate
[value box or chart code here]
## Column {data-width=650}
### Absence by Department
[chart code here]The orientation: columns setting means level-2 headings create columns; vertical_layout: fill causes panels to expand to fill the browser window. The data-width attribute controls relative column widths.
15.5.3 Value Boxes and Gauges
flexdashboard provides two components specifically designed for KPI display. Value boxes show a single number with an icon and optional color coding:
# Inside a flexdashboard panel:
avg_hours <- 6.8
flexdashboard::valueBox(
value = avg_hours,
caption = "Avg Monthly Absence Hours",
icon = "fa-clock",
color = ifelse(avg_hours > 8, "danger", "success")
)Gauges display a metric relative to a defined range with colored sectors:
# Inside a flexdashboard panel:
flexdashboard::gauge(
value = 72,
min = 0,
max = 100,
label = "% Below Chronic Threshold",
sectors = flexdashboard::gaugeSectors(
success = c(80, 100),
warning = c(60, 79),
danger = c(0, 59)
)
)Remember Few’s caution: a gauge uses considerable screen space for a single number. Use gauges only when the position-within-a-range metaphor adds genuine insight — such as showing progress toward a target. For most KPIs, a value box with a trend indicator is more space-efficient.
15.5.4 Interactive Charts with plotly
One of flexdashboard’s strengths is seamless integration with interactive plotting libraries. The plotly package converts static ggplot2 charts into interactive versions with hover tooltips, zoom, and pan — with a single function call (Sievert 2020). Built on top of the plotly.js library, the R package’s ggplotly() function takes any ggplot2 object (Wickham 2016) and produces an interactive HTML widget. Here is an example using the absenteeism dataset:
# Load the absenteeism data
absenteeism <- read.csv("data/Absenteeism_at_work.csv", sep = ";")
# Compute average absence hours by month
monthly <- absenteeism |>
filter(Month.of.absence > 0) |>
group_by(Month.of.absence) |>
dplyr::summarize(
avg_hours = mean(Absenteeism.time.in.hours, na.rm = TRUE),
.groups = "drop"
) |>
mutate(month_name = month.abb[Month.of.absence])
# Create an interactive chart suitable for a dashboard panel
p <- ggplot(monthly, aes(
x = reorder(month_name, Month.of.absence),
y = avg_hours
)) +
geom_col(fill = "steelblue") +
geom_hline(
yintercept = mean(monthly$avg_hours),
linetype = "dashed", color = "gray40"
) +
labs(
title = "Average Absence Hours by Month",
x = NULL, y = "Hours"
) +
theme_minimal()
ggplotly(p, tooltip = c("x", "y"))This chart would occupy a panel in a flexdashboard layout. The ggplotly() wrapper adds hover tooltips (showing the exact value for each bar) and zoom controls — interactivity that is particularly valuable in analytical dashboards where users explore patterns across time periods.