Extending shinysurveys with Custom Input Types

By Jonathan Trattner in R Shiny Packages shinysurveys

June 7, 2021

Motivation

The original idea for {shinysurveys} was to provide a select set of well-supported input types that are commonly used with surveys. However, shortly after the package was published on CRAN, additional input types were requested (see GitHub issue #6 or #18).

In order to make the package as light-weight as possible (minimize dependence on external code), I did not wish to implement any input types not native to {shiny}. I also did not want to rewrite the internals of {shinysurveys} whenever a new input-type was requested. As a solution, I developed a framework for custom inputs to allow users to include different input types that meet their use case. In the next section, I outline three examples of how to add custom input types.

As of now, custom inputs are only supported in the development version of {shinysurveys}, which can be installed as follows:1

# install.packages("remotes")
remotes::install_github("jdtrat/shinysurveys@extend-shinysurveys")
library(shinysurveys)

Examples

Adding a sliderInput

Consider the question “On a scale from 1-10, how much do you love sushi?”. An ideal input type would be {shiny}’s sliderInput. However, this is not natively supported by {shinysurveys} as the slider input requires multiple arguments, including a minimum, maximum, and starting value. To get around this, we can define a new input type using a new function extendInputType(). As in a typical shiny survey, we can define our question as follows:

# Define a question as normal with the `input_type` set to "slider", which is not natively supported by {shinysurveys}.

slider_question <- data.frame(
  question = "On a scale from 1-10, how much do you love sushi?",
  option = NA,
  input_type = "slider",
  input_id = "sushi_scale",
  dependence = NA,
  dependence_value = NA,
  required = TRUE
  )

This looks like:

question option input_type input_id dependence dependence_value required
On a scale from 1-10, how much do you love sushi? NA slider sushi_scale NA NA TRUE

If we try to define the user-interface component of the shiny application, we will get the following error which most commonly occurs when {shinysurveys} doesn’t recognize an input type.

library(shiny)
library(shinysurveys)

ui <- fluidPage(
  surveyOutput(df = slider_question,
               survey_title = "Testing the Slider Input")
)
## Error in FUN(X[[i]], ...): Input type 'slider' from the supplied data frame of questions is not recognized by {shinysurveys}.
##                 Did you mean to register a custom input extension with `extendInputType()`?

To overcome this, we can use extendInputType(). This function accepts two arguments. The first, input_type, is a string of the input type used in the questions data frame. The second is the input definition. Consider:

# Register a slider input to {shinysurveys} with a custom minimum and maximum value.

extendInputType(input_type = "slider", {
  shiny::sliderInput(
    inputId = surveyID(),
    label = surveyLabel(),
    min = 1,
    max = 10,
    value = 5
    ) 
})
## Input Type "slider" registered with {shinysurveys}. If the session restarts, you will need to re-register it.
## To see all registered input extensions, please call `shinysurveys::listInputExtensions()`.

Note the inputId and label are set to surveyID() and surveyLabel(), respectively. These are necessary helper functions to ensure that survey features such as required questions function properly. As such, all extensions need inputId = surveyID() and label = surveyLabel().

Now, when we try to define the user-interface, we don’t see any errors:

# By defining the input type above, this works! Yay!
ui <- fluidPage(
  surveyOutput(df = slider_question,
               survey_title = "Testing the Slider Input")
)

When running the full application, we see the following survey:

Adding a dateInput

As requested in issue #18, a user needed a dateInput with special restrictions for possible values (dates). The user’s reprex showed the error we saw earlier, because {shinysurveys} does not natively support “date” inputs. Consider again the following question:

# Define a question as normal with the `input_type` set to "date", which is not natively supported by {shinysurveys}.
date_question <- data.frame(
  question = "When do you graduate?",
  option = NA,
  input_type = "date",
  input_id = "grad_date",
  dependence = NA,
  dependence_value = NA,
  required = FALSE
  )

This looks like:

question option input_type input_id dependence dependence_value required
When do you graduate? NA date grad_date NA NA FALSE

As in the slider example, if we try to define the user-interface component of the shiny application, we will get the following error which most commonly occurs when {shinysurveys} doesn’t recognize an input type.

library(shiny)
library(shinysurveys)

ui <- fluidPage(
  surveyOutput(df = date_question,
               survey_title = "Testing the Date Input")
)
## Error in FUN(X[[i]], ...): Input type 'date' from the supplied data frame of questions is not recognized by {shinysurveys}.
##                 Did you mean to register a custom input extension with `extendInputType()`?

Using extendInputType() we can overcome this.

# Register a date input to {shinysurveys}, limiting possible dates to a twenty-day period.

extendInputType("date", {
  shiny::dateInput(
    inputId = surveyID(),
    value = Sys.Date(),
    label = surveyLabel(),
    min = Sys.Date()-10,
    max = Sys.Date()+10
  )
})
## Input Type "date" registered with {shinysurveys}. If the session restarts, you will need to re-register it.
## To see all registered input extensions, please call `shinysurveys::listInputExtensions()`.

Now, when we try to define the user-interface, we don’t see any errors:

# By defining the input type above, this works! Yay!
ui <- fluidPage(
  surveyOutput(df = date_question,
               survey_title = "Testing the Date Input")
)

When running the full application, we see the following survey:

Adding a sliderTextInput

Both of the previous examples showed how to extend {shinysurveys} with inputs native to the {shiny} package. What about other packages, though? Could you use any input type? Turns out, you can! Consider a special text-based slider input from the package {shinyWidgets}. This allows you to have text labels on a slider input, unlike the one built into {shiny}.

Consider the question “Please indicate how strongly you love sushi from ‘Fish? Yuck!’ to ‘Love of my life’.” We can define it as follows:

# Define a question as normal with the `input_type` set to "date", which is not natively supported by {shinysurveys}.
textSlider_question <- data.frame(
  question = "Please indicate how strongly you love sushi from 'Fish? Yuck!' to 'Love of my life'.",
  option = NA,
  input_type = "textSlider",
  input_id = "sushi_feelings",
  dependence = NA,
  dependence_value = NA,
  required = FALSE
  )

This looks like:

question option input_type input_id dependence dependence_value required
Please indicate how strongly you love sushi from ‘Fish? Yuck!’ to ‘Love of my life’. NA textSlider sushi_feelings NA NA FALSE

We define the “textSlider” extension below and see an error-free user-interface definiton:

extendInputType("textSlider", {
  shinyWidgets::sliderTextInput(
    inputId = surveyID(),
    label = surveyLabel(),
    force_edges = TRUE,
    choices = c("Love of my life", "Big fan", "I can eat it", "It's not cooked?", "Fish? Yuck!"),
    selected = "I can eat it"
  )
})
## Input Type "textSlider" registered with {shinysurveys}. If the session restarts, you will need to re-register it.
## To see all registered input extensions, please call `shinysurveys::listInputExtensions()`.
# By defining the input type above, this works! Yay!
ui <- fluidPage(
  surveyOutput(df = textSlider_question,
               survey_title = "Testing the Text Slider Input")
)

When running the full application, we see the following survey:

Conclusion

Thanks for reading my blog post! I hope you’ll find this new feature of {shinysurveys} useful. If you have any feedback, I’d love for you to file an issue. For more of my work, please check out my GitHub. If you want to chat about anything (including neuroscience, #rstats, piano, or my cat), DM me on Twitter. Need help with an #rstats or {shiny} project? I’m available for consulting – just send me an email!


  1. Note: shinysurveys v0.2.0 was released on CRAN on July 11th, 2021. You can install it and use the same features described here with install.packages("shinysurveys").↩︎