Skip to contents

Draw a character with a mood, a status line and an optional message bubble. Until the app sets its own status text, the status line shows the character's line for the mood (the status column of mascot_moods(character)). mascot_status() with no text hands the status back to the mood.

Usage

mascot(
  id,
  ...,
  character = "tessa",
  mood = "idle",
  status = NULL,
  bubble = NULL,
  size = 160,
  placement = "bottom-right",
  theme = NULL,
  motion = TRUE,
  click = NULL
)

Arguments

id

A required non-empty string without whitespace, unique on the page. In a Shiny module use ns("helper") in the UI and "helper" in the server; update_mascot() adds the module namespace once.

...

Must be empty. Forces the arguments after it to be named.

character

A character id such as "tessa", or a mascot_character() helper (Knurl and Neer are experimental). Defaults to "tessa". NULL is not accepted.

mood

A mood name or mascot_mood() object. Defaults to "idle". See mascot_moods() for available choices. NULL is not accepted.

status

A non-empty string or mascot_status() object. NULL (the default) follows the mood. Text is always escaped, even inside htmltools::HTML().

bubble

A non-empty string, an htmltools tag or tag list, or a mascot_bubble() object. NULL (the default) shows no bubble. A plain string gets the defaults of mascot_bubble(): five seconds and a close button. Plain text is escaped; htmltools::HTML() or tags supply HTML. Tags with dependencies or head content are not supported.

size

A finite number of CSS pixels (at least 24), a positive percentage string such as "20%", or a mascot_size() object. Defaults to 160. Percentages follow the parent width when inline and the window width when floating, with a 24-pixel floor. On screens at most 575.98 CSS pixels wide, floating mascots scale down to a phone size by default ("auto"), while inline mascots stay unchanged. Pass mascot_size() with small_screen = NULL to keep the same size everywhere. NULL is not accepted.

placement

"bottom-right" (the default), "inline", a corner such as "top-left", a named list such as list(position = "top-left", minimise = TRUE, drag = "snap"), or a mascot_placement() object. Floating mascots show a minimise control by default; dragging is off. Inline mascots sit in the page flow and ignore minimise and drag. If you set either one yourself, a message says so; the defaults give no message. With drag, visitors can also drag the minimised restore button; each drop sets input$<id>_position to the corner ("snap") or a list with x and y ("free", experimental); saving it between visits is the app's job. See mascot_placement(). NULL is not accepted.

theme

A palette id string from mascot_palettes(), a named list of colour roles, a bslib::bs_theme() or a mascot_theme() object. NULL (the default) keeps the character's own colours. A palette sets the base colours for light and dark mode; "original" selects the character's own colours. Roles you leave unset follow the character's rules.

motion

A logical flag or mascot_motion_settings() object. TRUE (the default) allows movement, unless the visitor prefers reduced motion. FALSE stops all movement, including panels, drag snapping, minimising and restoring. NULL is not accepted.

click

What a click on the mascot does in a Shiny app. NULL (the default) does nothing: the mascot is a picture, and keyboard focus skips it. A label that is not blank, such as "Open help", or a mascot_action() object makes it a button for one action of your app. A mascot_popup_menu() object makes it open a menu, whose choice sets input$<id>_menu. With a click, each time the visitor activates the action, input$<id>_click is set (see Details).

Value

An htmltools tag with the mascot's web dependency attached.

Details

In mascot() and its helpers, NULL (where accepted) means none or the default; in update_mascot() it means unchanged. An empty helper (mascot_bubble(), mascot_status(), mascot_theme(), mascot_action() or mascot_popup_menu()) resets that setting.

mascot() and the helpers raise an error on an invalid value; update_mascot() warns instead and leaves the mascot unchanged. See mascot-package for condition classes.

Use the always visible status line for a short description of the current state. Use a bubble for a message about something that happened; it may time out. Use mascot_bubble(..., duration = Inf) for a message the user must act on, such as an invalid form, because a timed message can vanish before it is read.

When minimised, the status remains available to screen readers. See mascot_placement() for restore controls and message timing.

In Shiny the mascot is also an input. input$<id> only tells the server that the mascot has appeared; its contents are internal, so do not rely on them.

In modules, golem and rhino apps. Use the module's ns() in the UI and its local id in the server. session$ns("helper") also works in the server; the namespace is not added twice. In nested modules, namespace the child module's id in the parent UI and call its server with the local child id. Inputs such as input$helper_menu, input$helper_click, input$helper_position and input$helper_minimised belong to that child module. A module can put the mascot in its UI and update it from its server:

helper_ui <- function(id) {
  ns <- shiny::NS(id)
  mascot(ns("helper"))
}
helper_server <- function(id) {
  shiny::moduleServer(id, function(input, output, session) {
    update_mascot("helper", mood = "happy")
  })
}

The same pattern works in the function-built app_ui() of a golem app and in rhino's app/view/ modules using shiny::moduleServer(). The package's scripts and styles are attached through htmltools::htmlDependency(), including with shiny::renderUI(), and shared by mascots on the page. A built-in character's data travels the same way, once per page for each character in use; a custom character's data stays inside its own tag. You do not need to copy any of the package's files into your app. Try mascot_example("golem") (requires golem) or mascot_example("rhino") (a plain Shiny structure without rhino or box).

Showing the mascot later. To add the mascot only when it is needed, build it in the server with shiny::renderUI() and place shiny::uiOutput() in the UI. Updates sent before it appears are kept until it does, so the first update_mascot() can run in the same observer:

library(shiny)
library(mascot)

ui <- fluidPage(
  actionButton("start", "Start the review"),
  actionButton("finish", "Finish"),
  uiOutput("helper_ui")
)

server <- function(input, output, session) {
  shown <- reactiveVal(FALSE)
  output$helper_ui <- renderUI({
    req(shown())
    mascot("helper", status = "Reviewing")
  })
  observeEvent(input$start, {
    shown(TRUE)
    # Sent before the mascot exists: kept until it appears.
    update_mascot("helper", mood = "thinking")
  })
  observeEvent(input$finish, {
    update_mascot("helper", mood = "happy", status = "Review complete")
  })
}

shinyApp(ui, server)

The reactiveVal() makes the mascot appear once: clicking Start the review again does not rebuild it, so it keeps its mood and position.

Clicks. With click, the mascot is a button: an action named by its label, or a menu. Each time the visitor activates the action (a click or tap, Enter or Space while it has keyboard focus, or a screen reader's activate command), input$<id>_click is set to the number of activations since the mascot appeared, so shiny::observeEvent(input$helper_click, ...) runs each time for an action. Opening and closing a menu never sets this input. Dragging a floating mascot never counts as a click. See mascot_action() and mascot_popup_menu().

See also

update_mascot()

Other mascots in Shiny: update_mascot()

Examples

ui <- mascot("helper", mood = "happy")
ui <- mascot("small", size = 96, placement = "bottom-right")
ui <- mascot("responsive", size = mascot_size(120, small_screen = 48))
ui <- mascot("still", motion = FALSE)
ui <- mascot("helpful", click = "Open help")
if (FALSE) { # interactive()
shiny::shinyApp(
  ui = shiny::fluidPage(mascot("helper")),
  server = function(input, output, session) {}
)
}