rstudio / bslib

Tools for theming Shiny and R Markdown via Bootstrap 3, 4, or 5.
https://rstudio.github.io/bslib/
Other
475 stars 57 forks source link

`selectInput()`'s dropdown clipped inside a `card()` #622

Open DavideMagno opened 1 year ago

DavideMagno commented 1 year ago

Hi, thanks a lot for release 0.5, it looks very neat!

One question: I have a selectInput in a card, but since it's very long it requires scrolling as it doesn't overlap with other cards. This is a fundamentally different behaviour as the "box" ui in shinydashboard, which I very much liked.

How can I make it work the same in bslib?

Screenshot 2023-06-08 alle 19 59 06

Cheers, Davide

gadenbuie commented 1 year ago

This was also reported in #502 where the proposed workaround is to add style = "overflow: visible" to the card() and card_body() with the long select input menu. If you have htmltools loaded, you can use style = css(overflow = "visible").

That's not the most user-friendly approach, but it's a reasonable path to take given that setting overflow: visible for all cards wouldn't be a good default setting.

Here are two demo apps based on the example in #502. With shinydashboard:

library(shiny)
library(htmltools)
library(shinydashboard)
server <- function(input, output) { }

ui_sd <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    box(
      selectInput("test", label = NULL, choices = colnames(mtcars))
    ),
    box(
      selectInput("test1", label = NULL, choices = colnames(mtcars))
    )
  )
)

shinyApp(ui_sd, server)

And here's a similar app with bslib:

# With {bslib} ---------------------------------------------------
library(shiny)
library(htmltools)
library(bslib)
server <- function(input, output) { }

ui_bslib <- fluidPage(
  theme = bslib::bs_theme(version = 5),
  card(
    style = css(overflow = "visible"),
    card_body(
      style = css(overflow = "visible"),
      selectInput("test", label = NULL, choices = colnames(mtcars))
    )
  ),
  selectInput("test1", label = NULL, choices = colnames(mtcars))
)

shinyApp(ui_bslib, server)
gadenbuie commented 1 year ago

Also reported on Posit Community: https://community.rstudio.com/t/selectinput-within-navs-tab-card-options-cut-off/163460

cpsievert commented 1 year ago

The overflow:visible trick will work for a single card(), but similar issues will occur if you put the card() in another parent container with overflow:auto. As a more general workaround, I'd recommend using selectizeInput()'s dropdownParent option:

ui <- page_fluid(
  card(
    selectizeInput(
      "test", label = NULL, choices = colnames(mtcars), 
      options = list(dropdownParent = "body")
    )
  ),
  selectInput("test1", label = NULL, choices = colnames(mtcars))
)

shinyApp(ui, function(...) { })
gadenbuie commented 1 year ago

That's neat (TIL)! Should we consider setting this option by default in shiny? (Is that technically possible?) Are there non-obvious downsides to setting this globally?

cpsievert commented 1 year ago

I feel like there might be some old issues that discuss it...I can't think of any reason not to off the top of my head, but I'm sure it has the potential to break legacy apps.

As a middle-ground solution, we could maybe consider defaulting to that option in the binding if we detect window.bootstap.VERSION >= 5?

gadenbuie commented 1 year ago

We actually added it and then removed it:

Maybe we could explore another approach to handle this in the select input binding

cpsievert commented 1 year ago

Ahh yea, this also made me realize that dropdownParent = "body" won't work with full_screen = TRUE (at least currently)

cpsievert commented 11 months ago

With the latest (dev) version of bslib, you can now do this (and count on it working reliably).

page_fluid(
  theme = bs_theme() |>
    bs_add_rules(c(
      ".card {overflow: visible !important;}",
      ".card-body {overflow: visible !important;}"
    )),
  card(
    selectizeInput("test", label = NULL, choices = colnames(mtcars))
  )
) |>
  shinyApp(function(...) { })

That said, it feels like we should make this easier, possibly through a card(scrolling = FALSE) argument?

gadenbuie commented 11 months ago

Another option is to use the overflow-visible helper class:

page_fluid(
  card(
    class = "overflow-visible",
    card_body(
      class = "overflow-visible",
      selectizeInput("test", label = NULL, choices = colnames(mtcars))
    )
  )
)