--- output: github_document --- ```{r setup, include=FALSE} knitr::opts_chunk$set(eval = FALSE) github_sha_link <- function(sha) { glue::glue("[{sha}](https://github.com/gadenbuie/js4shiny-frappeCharts/commit/{sha})") } ``` # Building a Shiny Input In this project, we're going to create a typing speed app using a custom Shiny input. The app will give users typing prompts, monitor their typing speed, and use a Frappe Chart line chart to show their speed over time as they type. ## Setup a folder for our app inside the frappeCharts package `r github_sha_link("113340074c3af9c2cdf46cd7787829d4ec56bfcf")` Create the directory `inst/shiny-input-app` and add `app.R` and `typing.js`. ```{r} usethis::use_directory("inst/shiny-input-app") file.create("inst/shiny-input-app/app.R") file.create("inst/shiny-input-app/typing.js") ``` ## Create a basic Shiny app with a typing area `r github_sha_link("ff3a962f7e6d16a75ebdb620aac0fdfc9949086e")` We'll start with typical Shiny inputs. ```r library(shiny) ui <- fluidPage( textAreaInput("typing", "Type here..."), verbatimTextOutput("debug") ) server <- function(input, output, session) { output$debug <- renderPrint(input$typing) } shinyApp(ui, server) ``` Run this app and type in the box. ## Create our own typingSpeedInput() Use Shiny's `textAreaInput()` to get the template for our own `typingSpeedInput()` ```{r, eval=TRUE} shiny_text_input <- shiny::textAreaInput( "INPUT", "LABEL", placeholder = "PLACEHOLDER" ) cat(format(shiny_text_input)) ``` ```{r} typingSpeedInput <- function(inputId, label, placeholder = NULL) { .label <- label htmltools::withTags( div( class = "form-group typing-speed", label(class = "control-label", `for` = inputId, .label), textarea(id = inputId, class = "form-control", placeholder = placeholder) ) ) } ``` Two points: 1. Notice that I used `htmltools::withTags()`, which makes it easier to write multiple tags at once. But it has the downside of masking the `label` argument of `typingSpeedInput()`. Hence, the first line `.label <- label`. 1. I added `.typing-speed` to our parent container so that we can find or style our custom input. Replace the `textAreaInput()` with our new `typingSpeedInput()` and run the app. It works the same! Wait, why? ```{r} ui <- fluidPage( # textAreaInput("typing", "Type here..."), typingSpeedInput("typing", "Type here..."), verbatimTextOutput("debug") ) ```