shiny 4 small textInput boxes side-by-side
Solution 1:
to paraphrase (and to simplify to the case of 2 inputs), your problem is that:
runApp(list(
ui = bootstrapPage(
textInput(inputId="xlimitsmin", label="x-min", value = 0.0),
textInput(inputId="xlimitsmax", label="x-max", value = 0.5)
),
server = function(input, output) {}
))
shows
But you want side-by-side small inputs, like so:
The short answer
textInputRow<-function (inputId, label, value = "")
{
div(style="display:inline-block",
tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "text", value = value,class="input-small"))
}
runApp(list(
ui = bootstrapPage(
textInputRow(inputId="xlimitsmin", label="x-min", value = 0.0),
textInputRow(inputId="xlimitsmax", label="x-max", value = 0.5)
),
server = function(input, output) {}
))
gives:
The long answer
Side-by-side inputs
Let's do side-by-side first:
Currently textInput generates two separate tags - the label
, and the input
, each of which is configured by CSS as display:block
, which means it's a rectangle that will break to the left side of the container. We need to wrap each textInput
's field in new container (div) and tell that container that the container that follows it (the next textInput
) is allowed to be on the same horizontal row on the page, using CSS's display:inline-block
.
So we add a div with a style around each textInput
:
runApp(list(
ui = bootstrapPage(
div(style="display:inline-block",textInput(inputId="xlimitsmin", label="x-min", value = 0.0)),
div(style="display:inline-block",textInput(inputId="xlimitsmax", label="x-max", value = 0.5))
),
server = function(input, output) {}
))
Small inputs
Now let's deal with small. There are a few ways to do small,
- make the font smaller,
- make the input box have fewer characters in it.
- tell css or (here) bootstrap to draw a smaller box
Since bootstrap.js
is really in control of layout when we use shiny, only 3 will reliably work, so let's use that.
Input sizes are documented in Bootstrap 2.3.2's CSS Forms documentation, under 'Control Sizing'. It includes a variety of sizes from mini, small, medium, large, xlarge, and xxlarge, and the default is probably medium. Let's try small, instead.
To set the size, we need to change the class of the input
tag generated by textInput
.
Now textInput
is just a convenience function around the more powerful tags
functions such as tags$label
and tags$input
. We can build a more powerful version of textInput
that allows us to configure the elements, specifically the class of the input
node:
textInput2<-function (inputId, label, value = "",...)
{
tagList(tags$label(label, `for` = inputId), tags$input(id = inputId,
type = "text", value = value,...))
}
runApp(list(
ui = bootstrapPage(
div(style="display:inline-block",textInput2(inputId="xlimitsmin", label="x-min", value = 0.0, class="input-small")),
div(style="display:inline-block",textInput2(inputId="xlimitsmax", label="x-max", value = 0.5, class="input-small"))
),
server = function(input, output) {}
))
And we are done - but we can roll some of this functionality up by having textInput3
generate the div tag. It could also set the class by itself, but I'll leave that for you to write.
Wrapping it up
textInput3<-function (inputId, label, value = "",...)
{
div(style="display:inline-block",
tags$label(label, `for` = inputId),
tags$input(id = inputId, type = "text", value = value,...))
}
runApp(list(
ui = bootstrapPage(
textInput3(inputId="xlimitsmin", label="x-min", value = 0.0, class="input-small"),
textInput3(inputId="xlimitsmax", label="x-max", value = 0.5, class="input-small")
),
server = function(input, output) {}
))
For interest's sake, here's the version using class input-mini
:
Solution 2:
Using Shiny (>= 0.11), you can accomplish this by putting the input calls within a splitLayout(). This will split the fluid row, box, etc. into the necessary columns required to show your input fields side-by-side.
The example below would give you three text inputs in a box, that will appear side-by-side in the fluidRow.
fluidRow(
box(width = 12, title = "A Box in a Fluid Row I want to Split",
splitLayout(
textInput("inputA", "The first input"),
textInput("inputB", "The second input"),
textInput("inputC", "The third input")
)
)
)