knitr::opts_chunk$set(eval = FALSE)
Shiny comes with a large library of input widgets for collecting input from the user and conveying input data to R.
If you want a kind of input not provided by Shiny — like a color picker, or a different kind of slider — you've always been able to build your own. Shiny's input system is extensible. All that's required is an understanding of certain conventions and a little custom JavaScript.
reactR provides additional tools to ease the creation of new Shiny inputs implemented using React. In the following tutorial, we will demonstrate these tools by implementing a new Shiny color picker input that wraps the react-color library.
In order to develop a reactR Shiny input, you'll need to install R and optionally RStudio. If you're on Windows, you should also install Rtools.
For an excellent general introduction to R package concepts, check out the R packages online book.
In addition, you'll need to install the following JavaScript tools on your machine:
node
and npm
commands.yarn
command.To follow along in this vignette, you'll also need the following R packages:
install.packages(c("shiny", "devtools", "usethis", "reactR"))
To create a new widget you can call scaffoldReactShinyInput
to generate the basic
structure and build configuration. This function will:
name
and version
elements. For example, the npm package
foo
at version ^1.2.0
would be expressed as list(name = "foo", version =
"^1.2.0")
. The package, if provided, will be added to the new widget's
package.json
as a build dependency.The following R code will create an R package named colorpicker, then
provide the templating for creating an input powered by the
react-color
library on npm:
# Create the R package (rstudio=TRUE is recommended if you're not already comfortable with your terminal) usethis::create_package("~/colorpicker", rstudio = TRUE) # Scaffold initial input implementation files withr::with_dir( "~/colorpicker", reactR::scaffoldReactShinyInput("colorpicker", list("react-color" = "^2.17.0"), edit = FALSE) )
The next step is to navigate to the newly-created colorpicker
project and run
the following commands in the terminal. If you're new the terminal, we recommend opening your newly created RStudio ~/colorpicker/colorpicker.Rproj
project file, then running the following in the RStudio terminal tab:
yarn install yarn run webpack
yarn install
downloads all of the dependencies listed in package.json
and
creates a new file, yarn.lock
. You should add this file to revision control.
It will be updated whenever you change dependencies and run yarn install
.
Note: you only need to run it after modifying package.json. For further
documentation on yarn install
, see the yarn
documentation.
yarn run webpack
compiles the modern JavaScript
with JSX source file at srcjs/colorpicker.jsx
into
www/colorpicker/colorpicker/colorpicker.js
. The latter file is the one
actually used by the R package and includes all the relevant JavaScript
dependencies in a dialect of JavaScript that most browsers understand.
yarn run webpack
is not strictly a yarn
command. In fact, yarn run
simply
delegates to the webpack program. Webpack's
configuration is generated by scaffoldReactShinyInput
in the file
webpack.config.js
, but you can always change this configuration and/or modify
the yarn run webpack
command to suit your needs.
Now that the input's JavaScript is compiled, go ahead and install the R package:
devtools::document() devtools::install(quick = TRUE)
In RStudio, you can use the keyboard shortcuts Ctrl-Shift-D
and
Ctrl-Shift-B
to document and build the package. (On macOS, the shortcuts are
Cmd-Shift-D
and Cmd-Shift-B
)
Now that the input's JavaScript is compiled, and the R package is installed,
run app.R
to see a demo in action:
shiny::runApp()
In RStudio, you can open app.R
and press Ctrl-Shift-Enter
(Cmd-Shift-Enter
on macOS). You should see something like the following appear
in the Viewer pane:
At this point, we have a working (if simple) React-powered text input.
Let's modify it to create an interface to the react-color
library.
Consider the following example taken from the react-color documentation.
import React from 'react'; import { SketchPicker } from 'react-color'; class Component extends React.Component { render() { return <SketchPicker />; } }
That JavaScript code produces a SketchPicker
-type interface that looks like
this:
However, that example doesn't demonstrate a way to default to a particular
color, or a way to cause something to happen when the color changes. To
accomplish these, react-color
components can optionally
take the following
props:
color
: accepts a
string of a hex color like '#333'
onChangeComplete
:
accepts a JavaScript function taking a single argument, the new color
, that
will be called when the new color is selectedSince this React component calls a configurable function (i.e., onChangeComplete
) when the input (i.e., color) value changes, we can supply a function to inform Shiny about these changes. You could, in theory, do this by writing your own custom Shiny input wrapper around this component, but reactR
provides some conventions to make it much easier. These conventions have two main parts (R and JavaScript):
reactR::createReactShinyInput()
to construct the user-facing R input and route any user-supplied options (e.g., the default
input value and other configuration
) to the React component. This part was already done for us in the R/colorpicker.R
file of our colorpicker project:colorpickerInput <- function(inputId, default = "") { reactR::createReactShinyInput( inputId = inputId, class = "colorpicker", dependencies = htmltools::htmlDependency( name = "colorpicker-input", version = "1.0.0", src = "www/colorpicker/colorpicker", package = "colorpicker", script = "colorpicker.js" ), default = default, configuration = list(), container = htmltools::tags$span ) }
Design an intermediate React component that routes information from colorpickerInput()
to the <SketchPicker>
component and also inform Shiny when a new color is chosen. This intermediate component should be a functional component with three arguments:
configuration
: The JSON equivalent of the configuration
argument from reactR::createReactShinyInput()
. In this particular example, configuration
isn't used.
value
: The input's values over time, beginning with the default
supplied from reactR::createReactShinyInput()
.setValue
: A JavaScript function to call with the input's new value when one is created. This function is not user supplied, but rather an internal hook for informing Shiny about changes to the component's current state (i.e. value). Consider the following intermediate component, PickerInput
. Note how this intermediate component allows one to set the default value
from R and also calls setValue()
inside onChangeComplete
in order to inform Shiny about new color values. Finally, reactR.reactShinyInput()
registers this intermediate component as a custom Shiny input binding named colorpicker
.
import { reactShinyInput } from 'reactR'; import { SketchPicker } from 'react-color'; const PickerInput = ({ configuration, value, setValue }) => { return ( <SketchPicker color={ value } onChangeComplete={ color => setValue(color.hex) } /> ); }; // Note the first argument here should match the `class` // argument of the reactR::createReactShinyInput() from step 1 reactShinyInput('.colorpicker', 'colorpicker', PickerInput);
Open the srcjs/colorpicker.jsx
file in your colorpicker project and paste this code into it. After saving the file, run yarn run webpack
in the terminal, re-install the
package, then run shiny::runApp()
again
When you select new colors, you should see the textOutput
update accordingly.
You might have noticed that the input showed up initially without a color
selected. That's because in app.R
we didn't supply a default
argument to the
colorpickerInput
function inside our ui
.
Try replacing the call to colorpickerInput
with this:
colorpickerInput("textInput", default = "#a76161")
Now when you run the app, the color should start as a shade of red.
This tutorial walked you through the steps taken to wrap the react-color
library in a Shiny input. The full example package is accessible at
https://github.com/react-R/colorpicker-example. Our intention is keep creating
example packages under the https://github.com/react-R organization, so head
there if you'd like to see other examples of interfacing with React.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.