shinyalert
lets you easily create pretty popup messages (modals) in
Shiny.
Modals can contain text, images, OK/Cancel buttons, an input to get a response from the user, and many more customizable options. A modal can also have a timer to close automatically. The value of the modal can be retrieved in Shiny using an input or using callback functions. See the demo Shiny app online for examples.
If you need any Shiny help, I’m available for consulting. If you find shinyalert useful, please consider supporting my open-source development.
- Examples
- Overview
- Installation
- Input modals
- Modal return value
- Callbacks
- Chaining modals
- Using in Rmarkdown files
- Comparison with Shiny modals
- Contributions
Example 1: Simple modal
Example 2: Input modal
Example 3: Chaining modals
shinyalert
uses the sweetalert
JavaScript library to create simple and elegant popups (modals) in
Shiny.
Simply call shinyalert()
with the desired arguments, such as a title
and text, and a modal will show up. In order to be able to call
shinyalert()
in a Shiny app, you must first call useShinyalert()
anywhere in the app’s UI.
Here is some minimal Shiny app code that creates a modal:
library(shiny)
library(shinyalert)
ui <- fluidPage(
useShinyalert(), # Set up shinyalert
actionButton("preview", "Preview")
)
server <- function(input, output, session) {
observeEvent(input$preview, {
# Show a modal when the button is pressed
shinyalert("Oops!", "Something went wrong.", type = "error")
})
}
shinyApp(ui, server)
To install the stable CRAN version:
install.packages("shinyalert")
To install the latest development version from GitHub:
install.packages("remotes")
remotes::install_github("daattali/shinyalert")
Usually the purpose of a modal is simply informative, to show some
information to the user. However, the modal can also be used to retrieve
an input from the user by setting the type = "input"
parameter.
Only a single input can be used inside a modal. By default, the input
will be a text input, but you can use other HTML input types by
specifying the inputType
parameter. For example, inputType = "number"
will provide the user with a numeric input in the modal.
See the Modal return value and Callbacks sections below for information on how to access the value entered by the user.
Modals created with shinyalert
have a return value when they exit.
When there is an input field in the modal (type="input"
), the value of
the modal is the value the user entered. When there is no input field in
the modal, the value of the modal is TRUE
if the user clicked the “OK”
button, and FALSE
if the user clicked the “Cancel” button.
When the user exits the modal using the Escape key or by clicking
outside of the modal, the return value is FALSE
(as if the “Cancel”
button was clicked). If the timer
parameter is used and the modal
closes automatically as a result of the timer, no value is returned from
the modal.
The return value of the modal can be accessed via input$shinyalert
(or
using a different input ID if you specify the inputId
parameter) in
the Shiny server’s code, as if it were a regular Shiny input. The return
value can also be accessed using the modal callbacks.
The return value of the modal is passed as an argument to the
callbackR
and callbackJS
functions (if a callbackR
or callbackJS
arguments are provided). These are functions that get called, either in
R or in JavaScript, when the modal exits.
For example, using the following shinyalert
code will result in a
modal with an input field. After the user clicks “OK”, a hello message
will be printed to both the R console and in a native JavaScript alert
box. You don’t need to provide both callback functions, but in this
example both are used for demonstration.
shinyalert(
"Enter your name", type = "input",
callbackR = function(x) { message("Hello ", x) },
callbackJS = "function(x) { alert('Hello ' + x); }"
)
Notice that the callbackR
function accepts R code, while the
callbackJS
function uses JavaScript code.
Since closing the modal with the Escape key results in a return value of
FALSE
, the callback functions can be modified to not print hello in
that case.
shinyalert(
"Enter your name", type = "input",
callbackR = function(x) { if(x != FALSE) message("Hello ", x) },
callbackJS = "function(x) { if (x !== false) { alert('Hello ' + x); } }"
)
It’s possible to chain modals (call multiple modals one after another)
by making a shinyalert()
call inside a shinyalert callback or using
the return value of a previous modal. For example:
shinyalert(
title = "What is your name?", type = "input",
callbackR = function(value) { shinyalert(paste("Welcome", value)) }
)
You can use shinyalert
in Rmarkdown documents by using the rmd = TRUE
parameter. This only works in interactive Rmd documents (when
runtime: shiny
is used in the YAML).
---
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
```
```{r}
library(shinyalert)
useShinyalert(rmd = TRUE)
textInput("name", "Name")
actionButton("button", "Click me")
observeEvent(input$button, {
shinyalert(title = "Hey", text = input$name)
})
```
Doesn’t Shiny already have support for modals?
Yes, it does.
And Shiny’s modals are more powerful in some ways than shinyalert
modals: Shiny’s native modals (showModal()
+modalDialog()
) can
contain multiple input fields and even outputs.
I created shinyalert
for two reasons: first of all, I started working
on it well before Shiny had modals. But I decided to keep working on it
and release it even afterwards because I find shinyalert
to be easier
to use and to result in much nicer modals. There are also some extra
features in shinyalert
, such as the callback functions and the timer.
But ultimately it’s a matter of convenience and aesthetics.
If you have any suggestions or feedback, I would love to hear about it. You can either message me directly, open an issue if you want to request a feature/report a bug, or make a pull request if you can contribute.
Lastly, if you find shinyalert useful, please consider supporting me for the countless hours I’ve spent building, documenting, and supporting various open-source packages :)
If you’re interested in the history of this package, you can read the blog post I created when releasing the package.