shiny
shiny copied to clipboard
add a class to an input (feature request)
Hello,
The numeric inputs "top" and "right" below have the class input-sm:
I find them better than the two other default numeric inputs, which are too big.
I had to add this class with the help of jQuery, because there's no way to add a class with the numericInput function. It would be nice to have an argument class (or addClass) for the inputs.
We may do this at some point, but it's not in the works right now.
However, I just wanted to point out that you don't need to use jQuery for this. Do you know the shinyjs package? (In a nutshell: "shinyjs lets you perform common useful JavaScript operations in Shiny apps that will greatly improve your apps, without having to know any JavaScript") There's an addClass() function there that does exactly what you want. See this overview page: http://deanattali.com/shinyjs/overview. There's a demo at the end that shows you common shinyjs operations in an interactive demo.
Hello @bborgesr
Yes I know shinyjs, but indeed I didn't think to use it. Thank you for the reminder.
@stla FYI you don't have to rely on javascript, you can manipulate the tag right in the UI. It's a little bit hacky because it uses knowledge of what an input tag from shiny looks like, which isn't guaranteed to remain stable forever, but you can use code like this
library(shiny)
library(magrittr)
smallInput <- function(tag) {
tag$children[[2]] <- htmltools::tagAppendAttributes(tag$children[[2]], class = "input-sm")
tag
}
ui <- fluidPage(
textInput("small", "small", "") %>% smallInput(),
textInput("normal", "normal", "")
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
I think both of these solutions are 'hacky'. Adding classes to the inputs seems useful enough to have native integration. I have not looked into other inputs, but if they are as easy as the example I show below, it seems like it should be easy to implement as well. Any thoughts on this idea?
This is a tweak of the infoBox function which adds a classes argument to the function. This argument takes a list of classes to be added to the input.
infoBox <- function (title, value = NULL, subtitle = NULL, icon = shiny::icon("bar-chart"),
color = "aqua", width = 4, href = NULL, fill = FALSE, classes = NULL)
{
validateColor(color)
tagAssert(icon, type = "i")
colorClass <- paste0("bg-", color)
# allow the addition of extra classes to the div
boxContent <- div(class = paste(c("info-box", classes), collapse = ' '), class = if (fill)
colorClass, span(class = "info-box-icon", class = if (!fill)
colorClass, icon), div(class = "info-box-content", span(class = "info-box-text",
title), if (!is.null(value))
span(class = "info-box-number", value), if (!is.null(subtitle))
p(subtitle)))
if (!is.null(href))
boxContent <- a(href = href, boxContent)
div(class = if (!is.null(width))
paste0("col-sm-", width), boxContent)
}
as an example:
infoBox("Hello", 3, classes='shadow')
<div class="col-sm-4">
<div class="info-box shadow">
<span class="info-box-icon bg-aqua">
<i class="fa fa-bar-chart"></i>
</span>
<div class="info-box-content">
<span class="info-box-text">Hello</span>
<span class="info-box-number">3</span>
</div>
</div>
</div>
Yes the solutions we proposed are hacky but are the only way to achieve it without altering the shiny codebase, until this feature gets added
Sorry, I was not very clear. I am meaning to suggest a method as to how this can be integrated into the codebase. I have never contributed to an open source project before, but I would be a happy to make an attempt on this.
Before embarking, however, I am hoping to get some feedback as to the viability of this implementation from those who are more knowledgeable about the code base. Maybe I should just go for and see what happens, but that seems reckless.
I would very much like to see this feature as well for all inputs. We can already add custom classes to actionButtons very easily.
I frequently want to change the appearance of several textInputs via CSS and for now have to rely on either shinyjs::addClass, adding css to the ids or need to wrap them in divs + more complex css selectors. And I would very much prefer to just have a custom class added + css.
The class is form-control-sm for Bootstrap 4, not input-sm.
Here is a less hacky way:
library(shiny)
library(htmltools)
tagQ <- tagQuery(numericInput("id", "LABEL", value = 100))
tagQ$find("input")$addClass("input-sm form-control-sm")$allTags()
Using tagQuery() is indeed a nice clean approach. It should be noted though that it's a "new" function that only became available in htmltools version 0.5.2 from August 2021.