Upgrade notes for Shiny 1.14.0
New features
New
startApp()runs a Shiny app in non-blocking mode, returning aShinyAppHandleobject withstop(),status(),url(), andresult()methods. When a new app is started, any previously running non-blocking app is automatically stopped. (#4349)session$destroy()andsession$onDestroy()are now available on module session proxies to clean up “dangling reactivity” when dynamic module UI is removed. Callingsession$destroy()invokes all registeredonDestroy()callbacks for that scope and its descendants, tearing down reactive values, expressions, and observers. A parent can also destroy a child module scope by id withsession$destroy(id), so it can tear down a module using the same id it used to insert the UI (#4372).downloadButton()anddownloadLink()gain a newenabledparameter. The default value,"auto", automatically enables the button/link when the download is ready. To opt-into manual state management (e.g.,shinyjs::enable()), setenabledtoFALSE(orTRUE). (#4119)
Improvements
Output resize/visibility detection now uses native browser observers (
ResizeObserver,IntersectionObserver) instead of relying on jQueryshown/hiddenevents andwindow.resize. This makes Shiny’s client-side output-info pipeline (image/plot sizing, hidden-state tracking, theme reporting) work automatically in any layout — including CSS-only show/hide, third-party tab components, and non-Bootstrap frameworks — without requiring custom event hooks. This also introduces ashiny:themechangeevent for code that needs to trigger theme clientdata refreshes after changing surrounding visual theme context. (#3682)conditionalPanel()no longer briefly flashes its contents on app start when the condition is initiallyFALSE. (#3505)Updated default HTTP headers for better security. Shiny now sends
X-Content-Type-Options: nosniffinstead of the legacyX-UA-Compatibleheader. This removes outdated Internet Explorer–specific behavior and adds a modern safeguard that prevents browsers from misinterpreting file types. (#4385)Removed
InputBinding.dispose()from the JavaScriptInputBindingclass. This method was never called by Shiny’s runtime, so any overrides were dead code. Useunsubscribe()for cleanup logic instead. (#4375)
Bug fixes
Loading shiny no longer creates
.Random.seedin the global environment as a side effect. (#4382)need()now gives a clearer error when called without either amessageorlabelargument, instead of the cryptic “argument”label” is missing, with no default”. (thanks @chasemc and @sundrelingam, #2509)Clarified
varSelectInput()documentation to explain that the input returns a symbol for use with tidy evaluation, and fixed a grammatical typo. (#2334)