--- title: "Extending shinysurveys with Custom Input Types" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending shinysurveys with Custom Input Types} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(shinysurveys) library(tibble) ``` > Note: This is a pared down version of an article originally posted on [my personal blog](https://www.jdtrat.com/blog/extending-shinysurveys/). I plan to update documentation there more regularly than in the vignettes. # 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](https://github.com/jdtrat/shinysurveys/issues/6) or [\#18](https://github.com/jdtrat/shinysurveys/issues/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 two examples of how to add custom input types. # 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: ```{r define-question} # 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: ```{r echo = FALSE} slider_question ``` 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. ```{r demo-slider-without-extension, error = TRUE} library(shiny) library(shinysurveys) ui <- fluidPage( surveyOutput(df = slider_question, survey_title = "Testing the Slider Input") ) ``` 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: ```{r extend-input-type-slider} # 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 ) }) ``` 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: ```{r demo-slider-input} # 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: ![](graphics/custom-input-extensions/slider_input.png) ## Adding a `dateInput` As requested in issue [\#18](https://github.com/jdtrat/shinysurveys/issues/18), a user needed a `dateInput` with special restrictions for possible values (dates). [The user's reprex](https://github.com/jdtrat/shinysurveys/issues/18#issue-856073749) showed the error we saw earlier, because {shinysurveys} does not natively support "date" inputs. Consider again the following question: ```{r define-date-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: ```{r echo = FALSE} date_question ``` 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. ```{r demo-date-without-extension, error = TRUE} library(shiny) library(shinysurveys) ui <- fluidPage( surveyOutput(df = date_question, survey_title = "Testing the Date Input") ) ``` Using `extendInputType()` we can overcome this. ```{r extend-input-type-date} # 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 ) }) ``` Now, when we try to define the user-interface, we don't see any errors: ```{r demo-date-input} # 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: ![](graphics/custom-input-extensions/date_input.png)