Files
shiny/R/input-action.R
Carson Sievert ecf6bfe9a7 Put actionButton()s icon and label into containers (#4249)
* Put action icon and label into containers

* Update snaps

* More robust test

* Don't include container if icon/label isn't specified

* `yarn build` (GitHub Actions)

* Send HTML string/deps on update; update news

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2025-07-14 16:22:03 -05:00

123 lines
3.3 KiB
R

#' Action button/link
#'
#' Creates an action button or link whose value is initially zero, and increments by one
#' each time it is pressed.
#'
#' @inheritParams textInput
#' @param label The contents of the button or link--usually a text label, but
#' you could also use any other HTML, like an image.
#' @param icon An optional [icon()] to appear on the button.
#' @param disabled If `TRUE`, the button will not be clickable. Use
#' [updateActionButton()] to dynamically enable/disable the button.
#' @param ... Named attributes to be applied to the button or link.
#'
#' @family input elements
#' @examples
#' ## Only run examples in interactive R sessions
#' if (interactive()) {
#'
#' ui <- fluidPage(
#' sliderInput("obs", "Number of observations", 0, 1000, 500),
#' actionButton("goButton", "Go!", class = "btn-success"),
#' plotOutput("distPlot")
#' )
#'
#' server <- function(input, output) {
#' output$distPlot <- renderPlot({
#' # Take a dependency on input$goButton. This will run once initially,
#' # because the value changes from NULL to 0.
#' input$goButton
#'
#' # Use isolate() to avoid dependency on input$obs
#' dist <- isolate(rnorm(input$obs))
#' hist(dist)
#' })
#' }
#'
#' shinyApp(ui, server)
#'
#' }
#'
#' ## Example of adding extra class values
#' actionButton("largeButton", "Large Primary Button", class = "btn-primary btn-lg")
#' actionLink("infoLink", "Information Link", class = "btn-info")
#'
#' @seealso [observeEvent()] and [eventReactive()]
#'
#' @section Server value:
#' An integer of class `"shinyActionButtonValue"`. This class differs from
#' ordinary integers in that a value of 0 is considered "falsy".
#' This implies two things:
#' * Event handlers (e.g., [observeEvent()], [eventReactive()]) won't execute on initial load.
#' * Input validation (e.g., [req()], [need()]) will fail on initial load.
#' @export
actionButton <- function(inputId, label, icon = NULL, width = NULL,
disabled = FALSE, ...) {
value <- restoreInput(id = inputId, default = NULL)
icon <- validateIcon(icon)
if (!is.null(icon)) {
icon <- span(icon, class = "action-icon")
}
if (!is.null(label)) {
label <- span(label, class = "action-label")
}
tags$button(
id = inputId,
style = css(width = validateCssUnit(width)),
type = "button",
class = "btn btn-default action-button",
`data-val` = value,
disabled = if (isTRUE(disabled)) NA else NULL,
icon, label,
...
)
}
#' @rdname actionButton
#' @export
actionLink <- function(inputId, label, icon = NULL, ...) {
value <- restoreInput(id = inputId, default = NULL)
icon <- validateIcon(icon)
if (!is.null(icon)) {
icon <- span(icon, class = "action-icon")
}
if (!is.null(label)) {
label <- span(label, class = "action-label")
}
tags$a(
id = inputId,
href = "#",
class = "action-button action-link",
`data-val` = value,
icon, label,
...
)
}
# Throw an informative warning if icon isn't html-ish
validateIcon <- function(icon) {
if (length(icon) == 0) {
return(icon)
}
if (!isTagLike(icon)) {
rlang::warn(
c(
"It appears that a non-HTML value was provided to `icon`.",
i = "Try using a `shiny::icon()` (or an equivalent) to get an icon."
),
class = "shiny-validate-icon"
)
}
icon
}