A brand new shiny package has entered the world yesterday: shinyalert
. It does only one thing, but does it well: show a message to the user in a modal (aka popup, dialog, or alert box). Actually, it can do one more thing: shinyalert
can also be used to retrieve an input value from the user using a modal.
You can visit the GitHub page or check out a demo online for yourself:
I usually release packages at version 0.1, but with shinyalert
I decided to be optimistic (read: naive) and release version 1.0. This package is fairly lightweight and I do not see it growing too much in terms of functionality, and because of its simplicity I don’t expect too many bugs. So I decided to start if off at 1.0 and my wishful thinking is that it could remain there without much ongoing maintenance. (Update only two weeks later: well, that 1.0 thing didn’t last very long. I’ve already added new features that were requested).
Table of contents
- Background
- Overview
- Input modals
- Modal return value
- Callbacks
- Chaining modals
- Comparison with Shiny modals
Background
The idea for this package has been on my mind for a very long time, and the basis for this package is a 10-liner that I wrote 2.5 years ago.
Back in mid 2015, when I was a graduate student spending 15 hours/day building Shiny apps and packages for fun, and maybe 15 minutes/day on my actual thesis (I will forever be grateful to Jenny Bryan for allowing me to get away with that), Kent Russell (@timelyportfolio) built an htmlwidget called sweetalertR
. It’s a port of the sweetalert JavaScript library, which is used to create simple pretty modals, to R.
Shortly after, Eric Nantz (@theRcast) asked Kent if it’s possible to incorporate these modals in Shiny apps, and tagged me in his question. I’d never heard of sweetalert before, but I was intrigued, so in my response I came up with a short piece of code to include sweetalert modals in Shiny apps.
Over the next year I noticed that I actually found these modals to be very nice so I started working on this package so that everyone could benefit from them. But it turned out that just a few weeks prior, Shiny released a great new version, which included support for modals! And so my motivation for the package quickly plummeted. I still wanted to release this package because I do believe it’s nicer and simpler than Shiny’s modals, and includes a few extra features. Last week, after a 16-month hiatus, I resumed its development.
And here we are!
Overview
shinyalert
uses the sweetalert JavaScript library to create simple and elegant 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.
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 the above 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)
Input modals
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.
Modal return value
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.
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); } }"
)
Chaining modals
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)) }
)
Comparison with Shiny modals
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 (or so I thought). 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.