# Shiny For R

> Building, styling, testing, debugging, or observing a Shiny for R app - library(shiny), shinyApp(), runApp(). Index skill: read this, then open the linked reference for the task. Covers reactivity (reactive/observe/req/isolate/bindEvent); modules; async promises and ExtendedTask; bslib layouts, navigation, cards, value boxes, and theming (incl. thematic and brand.yml); dynamic UI; plots with click/brush interaction; tables, file upload/download; notifications, modals, progress, validation; bookmarking; custom JS components; testServer testing; debugging; OpenTelemetry; and when to reach for DT, plotly, leaflet, shinychat, or shinytest2. Use when writing or changing any Shiny for R app, especially a dashboard, or when tempted to hand-roll what the framework provides - custom HTML tables, fake tabs, polling loops, blocking reactive work, or print-debugging server state.

- Skill: `rstudio/shiny-for-r` (Agent Skill, multi-file: 22 files)
- Install (CLI): `npx skillmds@latest add rstudio/shiny-for-r`
- Raw SKILL.md: https://api.skillmd.com/api/skills/rstudio/shiny-for-r/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: rstudio (https://skillmd.com/u/rstudio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/rstudio/shiny-for-r

---


# Shiny for R

A Shiny app has a `ui` object (or function), a `server(input, output,
session)` function, and `shinyApp(ui, server)` to run them together. The
reactive graph is the engine: reading a reactive source (`input$x`, a
`reactive()`, a `reactiveVal()`) inside a reactive context registers a
dependency, so changing that source re-runs everything that read it — you
never call outputs or schedule updates yourself.

This skill is an **index**. Find your task below and **read the linked
reference file before writing code** for that area. Read the one or two
references your task actually touches, not all of them.

Not every corner of Shiny has a reference here — plain inputs
(`selectInput()`, `actionButton()`, ...), deployment, and app performance
tuning are not covered. For those, work from your own knowledge of the
package and its help pages.

## Foundations

| Topic | Use when | Reference |
|---|---|---|
| Reactivity | A value should recompute or an output update as inputs change; choosing between `reactive()`/`observe()`/`observeEvent()`; `req()`, `isolate()`, `bindEvent()`, timers, polling | `references/reactivity.md` |
| Modules | A reusable, repeatable UI+server component; avoiding input/output id collisions across copies | `references/modules.md` |
| Session lifecycle | Per-session cleanup (`onSessionEnded()`), flush hooks, unhandled errors, per-session vs app-level scope, `session$userData` | `references/session-lifecycle.md` |

## Async

| Topic | Use when | Reference |
|---|---|---|
| Async | Returning a `promises::promise` from a render/observer so R keeps serving other sessions during slow I/O | `references/async.md` |
| Extended tasks | Running slow work in a background process while the session that started it stays fully interactive; task buttons | `references/extended-tasks.md` |

## Dashboard building

| Topic | Use when | Reference |
|---|---|---|
| Dashboard design | Turning a dataset or brief into a polished analytical dashboard; information hierarchy, shared filters, responsive layout, empty states, final visual/functional pass | `references/dashboard-design.md` |
| Dashboard components | Composing bslib `card()`, `value_box()`, `accordion()`, `tooltip()`/`popover()` instead of hand-rolled `div()` markup | `references/dashboard-components.md` |
| Layouts | Arranging a page with bslib `page_sidebar()`, `layout_columns()`, `card()` instead of nested `fluidRow()`/`column()` pyramids | `references/layouts.md` |

## Navigation & dynamic UI

| Topic | Use when | Reference |
|---|---|---|
| Navigation | Grouping switchable content into a real tab container/navbar instead of faking tabs with buttons plus `conditionalPanel()` | `references/navigation.md` |
| Dynamic UI | UI that must change after render — `update*Input()`, `conditionalPanel()`, `renderUI()`/`uiOutput()`, or `insertUI()`/`removeUI()` | `references/dynamic-ui.md` |

## Outputs

| Topic | Use when | Reference |
|---|---|---|
| Plots | Pairing `renderPlot()`/`plotOutput()` for base/lattice/ggplot2 graphics; click/hover/brush interaction via `nearPoints()`/`brushedPoints()` | `references/plots.md` |
| Tables | Choosing `renderTable()` (static), the deprecated `renderDataTable()`, or `DT`/`reactable` for sortable/searchable interactive tables | `references/tables.md` |
| Files | `fileInput()` uploads and `downloadHandler()`/`downloadButton()` generated-file downloads | `references/files.md` |

## Feedback & state

| Topic | Use when | Reference |
|---|---|---|
| Feedback | Toasts/notifications, modal dialogs, progress bars, and input validation sent from the server, typically inside `observeEvent()` | `references/feedback.md` |
| Bookmarking | Saving/restoring app state via a shareable URL instead of a hand-built query string or custom persistence layer | `references/bookmarking.md` |

## Theming, assets & extending

| Topic | Use when | Reference |
|---|---|---|
| Theming & assets | Setting `bslib::bs_theme()` Sass variables, `thematic` for plot theming, `brand.yml`, or adding custom CSS/JS/image assets | `references/theming-assets.md` |
| Custom components | Integrating a third-party JS widget or bespoke interaction when no built-in input/output covers it | `references/custom-components.md` |

## Testing & observability

| Topic | Use when | Reference |
|---|---|---|
| Testing | Verifying server-side reactive logic with `testServer()` without starting a real Shiny process or browser | `references/testing.md` |
| Debugging | Dropping into a real R debugger (`browser()`, error breakpoints) instead of `print()`-debugging a running reactive graph | `references/debugging.md` |
| OpenTelemetry | Tracing sessions, flush cycles, and reactive/observer/output executions instead of log-scraping or ad hoc timing | `references/opentelemetry.md` |
| Ecosystem | Deciding whether a companion package (DT, plotly, leaflet, shinychat, shinytest2, etc.) already solves the problem before hand-rolling it | `references/ecosystem.md` |

