shiny icon indicating copy to clipboard operation
shiny copied to clipboard

add a class to an input (feature request)

Open stla opened this issue 8 years ago • 10 comments

Hello,

The numeric inputs "top" and "right" below have the class input-sm:

capture

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.

stla avatar Sep 29 '17 08:09 stla

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.

bborgesr avatar Oct 05 '17 23:10 bborgesr

Hello @bborgesr Yes I know shinyjs, but indeed I didn't think to use it. Thank you for the reminder.

stla avatar Oct 10 '17 18:10 stla

@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)

daattali avatar Feb 27 '19 00:02 daattali

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>

Beachnad avatar Mar 14 '19 14:03 Beachnad

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

daattali avatar Mar 14 '19 15:03 daattali

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.

Beachnad avatar Mar 14 '19 16:03 Beachnad

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.

Jax89 avatar Dec 19 '19 10:12 Jax89

The class is form-control-sm for Bootstrap 4, not input-sm.

stla avatar Aug 12 '22 09:08 stla

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()

stla avatar Aug 20 '22 15:08 stla

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.

daattali avatar Aug 20 '22 17:08 daattali