Build a dynamic UI that reacts to user input
Shiny apps are often more than just a fixed set of controls that affect a fixed set of outputs. Inputs may need to be shown or hidden depending on the state of another input, or input controls may need to be created on-the-fly in response to user input.
Shiny currently has four different approaches you can use to make your interfaces more dynamic. From easiest to most difficult, they are:
conditionalPanelfunction, which is used in
ui.Rand wraps a set of UI elements that need to be dynamically shown/hidden.
renderUIfunction, which is used in
server.Rin conjunction with the
ui.R, lets you generate calls to UI functions and make the results appear in a predetermined place in the UI.
removeUIfunctions, which are used in
server.Rand allow you to add and remove arbitrary chunks of UI code (all independent from one another), as many times as you want, whenever you want, wherever you want.
Let’s take a closer look at each approach.
Showing and Hiding Controls With
Here’s an example for adding an optional smoother to a ggplot, and choosing its smoothing method:
In this example, the select control for
smoothMethod will appear only when the
smooth checkbox is checked. Its condition is
The condition can also use
output values; they work in the same way (
output.foo gives you the value of the output
foo). If you have a situation where you wish you could use an R expression as your
condition argument, you can create a reactive expression in the server function and assign it to a new output, then refer to that output in your
condition expression. If you do this, make sure to also set
outputOptions(output, [newOutputName], suspendWhenHidden = FALSE). (This is necessary because Shiny normally doesn’t send values to the browser for outputs that are hidden or not present in the UI. In this case, however, the browser does need to know the most up-to-date output value in order to correctly evaluate the condition of the
contitionalPanel function -
suspendWhenHidden = FALSE ensures this will happen.) For example:
However, since this technique requires server-side calculation (which could take a long time, depending on what other reactive expressions are executing) we recommend that you avoid using
output in your conditions unless absolutely necessary.
Creating Controls On the Fly With
Sometimes it’s just not enough to show and hide a fixed set of controls. Imagine prompting the user for a latitude/longitude, then allowing the user to select from a checklist of cities within a certain radius. In this case, you can use the
renderUI expression to dynamically create controls based on the user’s input.
renderUI works just like
renderText, and the other output rendering functions you’ve seen before, but it expects the expression it wraps to return an HTML tag (or a list of HTML tags, using
tagList). These tags can include inputs and outputs.
ui.R, use a
uiOutput to tell Shiny where these controls should be rendered.
Adding/removing UI with
Here’s a pretty simple example (also available here) of how one could use
removeUI to insert and remove text elements using a queue logic:
This function allows you to dynamically add an arbitrarily large UI object into your app, as many times as you want, whenever you want, wherever you want. Unlike
renderUI, the UI generated with
insertUI is not updatable as a whole: once it’s created, it stays there. Each new call to
insertUI creates more UI objects, in addition to the ones already there (all independent from one another). To update a part of the UI (ex: an input object), you must use the appropriate
render function or a customized
This function is particulaly useful when you want to build up an arbitrary list of stuff in the app’s UI. For example: you may have some data, and based on some input from the user (clicking buttons, selecting checkboxes, etc), you want to create and display a new model each time. But you don’t want to simply overwrite the previous model; you want to leave them there and continue adding new ones, so that your user can see the differences between them. If this is what you want, it’s a lot easier to use
insertUI instead of
renderUI, because each call to
ìnsertUI creates a new DOM element, rather than updating an existing one. Besides, you also get the flexibility of when and where to insert your UI.
Here’s a simple example:
selector argument determines the element relative to which your
ui should be inserted (it must be a string
s that is accepted by a jQuery
$(s) call). Once that is determined,
where refines the place to insert the
ui by offering four options relative to the
selector: “beforeBegin”, “afterBegin”, “beforeEnd” and “afterEnd”. The
ui itself can be anything that you usually put inside your apps’s ui function. One other argument that may be good to know about, but is not demoed above, is
multiple. In case your
selector matches more than one element,
multiple determines whether Shiny should insert the UI object relative to all matched elements or just relative to the first matched element (default).
As you can see, no special piece of code is needed inside the ui function for
insertUI to work. However, you will probably always need to pair your use of
insertUI with an
observeEvent that checks for some input change. This is necessary because, unlike the typical
insertUI has no idea when it should be called (it takes no reactive dependencies).
Note that, if you are inserting multiple elements in one call, you must wrap them in either a
tagList() or a
tags$div() (the latter option has the advantage that you can give it an id to make it easier to reference or remove it later on). If you want to insert raw html, use
ui = HTML().
This function allows you to remove any part of your UI. Once
removeUI is executed on some element, it is gone forever. While it may be a particularly useful pattern to pair this with
insertUI (to remove some UI you had previously inserted), there is no restriction on what you can use
removeUI on. Any element that can be selected through a jQuery selector can be removed through this function.
Here’s a simple example:
insertUI, you also have a
selector argument. This time, however, the
selector determines the element(s) themselves that you want to remove. If you want to remove a Shiny input or output, note that many of these are wrapped in
divs, so you may need to use a somewhat complex selector (as is indeed the case in the example above). You can avoid this if you wrap the inputs/outputs that you want to be able to remove easily in a
div with an id.
You also have a
multiple argument (again, not demoed here): in case your
selector matches more than one element,
multiple determines whether Shiny should remove all the matched elements or just the first matched element (default).
- Before making changes to the DOM that may include adding or removing Shiny inputs or outputs, call
- After such changes, call
If you are adding or removing many inputs/outputs at once, it’s fine to call
Shiny.unbindAll() once at the beginning and
Shiny.bindAll() at the end – it’s not necessary to put these calls around each individual addition or removal of inputs/outputs.
Here’s a short example of both non-reactive and reactive DOM manipulation:
For more on this topic, see the following resources:
If you have questions about this article or would like to discuss ideas presented here, please post on RStudio Community. Our developers monitor these forums and answer questions periodically. See help for more help with all things Shiny.