Skip to content

Modals show below full-screened cards #1360

Closed

Description

@bastianolea

System details

Output of sessionInfo():

R version 4.6.1 (2026-06-24)
Platform: x86_64-apple-darwin23.6.0
Running under: macOS Sonoma 14.6.1

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /usr/local/Cellar/r/4.6.1/lib/R/lib/libRlapack.dylib;  LAPACK version 3.12.1

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Santiago
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] bslib_0.12.0 shiny_1.14.0

loaded via a namespace (and not attached):
 [1] jsonlite_2.0.0    dplyr_1.2.1       compiler_4.6.1    promises_1.5.0    tidyselect_1.2.1  Rcpp_1.1.2        later_1.4.8      
 [8] jquerylib_0.1.4   fastmap_1.2.0     mime_0.13         R6_2.6.1          generics_0.1.4    curl_8.0.0        httr2_1.3.0      
[15] tibble_3.3.1      ellmer_0.4.2      pillar_1.11.1     rlang_1.3.0       cachem_1.1.0      httpuv_1.6.17     fs_2.1.0         
[22] sass_0.4.10       S7_0.2.2          otel_0.2.0        memoise_2.0.1     cli_3.6.6         withr_3.0.3       magrittr_2.0.5   
[29] digest_0.6.39     rstudioapi_0.19.0 xtable_1.8-8      lifecycle_1.0.5   coro_1.1.0        vctrs_0.7.3       glue_1.8.1       
[36] tools_4.6.1       pkgconfig_2.0.3   htmltools_0.5.9  

Example application or steps to reproduce the problem

Minimal reproducible example:

library(shiny)
library(bslib)

ui <- page_fillable(
  card(max_height = 300,
    full_screen = TRUE,
    card_header("Card example with fullscreen + modal"),
    card_body(
      p("Full screen this card first, then press", em("open modal")),
      actionButton("open_modal", "Open modal"),
      actionButton("show_notification", "Show notification")
    )
  )
)

server <- function(input, output, session) {
  observeEvent(input$open_modal, {
    showModal(
      modalDialog(
        title = "Detail",
        "Modal content.",
        easyClose = TRUE,
        footer = modalButton("Close")
      )
    )
  })

  observeEvent(input$show_notification, {
    showNotification("This is a sample notification.", type = "message")
  })
}

shinyApp(ui, server)

Describe the problem in detail

When making a bslib::card() show fullcreen, and then invoking a modal window with showModal(), modal appears below the full screen card. It should show up on top of the modal, as it is an interface element created after the full screen card. They should show on top of any other element, just like notifications currently do (this makes me believe this is a Shiny bug, not a bslib bug).

Minimal reproducible example shows exactly this behavior. Maybe Z-value of modal window should be higher than the full-screen card's.

Activity

  1. added
    Priority: MediumValid bug or well-defined request with moderate impact or a workaround.
    ai-triage:doneMarks an issue whose AI triage workflow is complete.
    on Sep 24, 2026
  2. transferred this issue fromrstudio/shinyon Oct 5, 2026
  3. added
    Priority: MediumValid bug or well-defined request with moderate impact or a workaround.
    ai-triage:doneMarks an issue whose AI triage workflow is complete.
    on Oct 5, 2026
  4. gadenbuie commented on Oct 5, 2026

    @gadenbuie
    Member

    Thanks @bastianolea. This turns out to be a bslib issue. Bootstrap assigns specific z-index levels to different element types

    Default z-index Element
    1000 Dropdowns
    1020 Sticky elements
    1030 Fixed elements, such as fixed navbars
    1040 Offcanvas backdrop
    1045 Offcanvas
    1050 Modal backdrop
    1055 Modal
    1070 Popovers
    1080 Tooltips
    1090 Toasts

    We are currently using 1070 for the full screen card, which means that it has higher z-index and shows above any modals. Reducing the full screen card z-index to 1055 would allow the modal to appear above the card, but it might introduce other problems. I'm looking into this...

  5. gadenbuie commented on Oct 5, 2026

    @gadenbuie
    Member

    Proposed stacking

    Treat a full-screen card as an overlay in the same family as offcanvas — an overlay on the rest of the app, not a tooltip-tier element. Start by using the offcanvas z-indexes directly; we'll only introduce adjustments if we find that causes problems:

    Layer z-index
    Offcanvas backdrop $zindex-offcanvas-backdrop (1040)
    Full-screen card $zindex-offcanvas (1045)
    Offcanvas $zindex-offcanvas (1045)
    Modal 1055
    Popover / tooltip 1070 / 1080

    Note that the card keeps the same backdrop-to-card relationship as the offcanvas pair (card exactly one tier above its own backdrop), and sits below modals, so modal dialogs (including Shiny showModal() progress indicators) cover the expanded card.

    Configurability: proxy through CSS custom properties so themes can adjust at runtime without recompiling Sass:

    • Card: z-index: var(--bslib-card-full-screen-z-index, #{$zindex-offcanvas})
    • Backdrop: z-index: var(--bslib-card-full-screen-backdrop-z-index, #{$zindex-offcanvas-backdrop})
    • Enter button: follows the card's variable

    Known accepted behavior changes: the page offcanvas backdrop no longer dims the full-screen card, and stray in-app dropdowns no longer show through the card.

    Transient UI dismissal

    A z-index alone can't hide open popovers/dropdowns from other parts of the app (their 1070+ would still paint above the card). That's a lifecycle problem, not a stacking one, so in enterFullScreen() (srcts/src/components/card.ts) we will dismiss all open Bootstrap Dropdown, Popover, and Tooltip instances whose trigger/element lives outside the card being expanded — including bslib's own web-component popover/tooltip implementations.

    Adjacent Cleanup

    • Remove the now-dead :has(bslib-offcanvas.show, ...) enter-button suppression rule in inst/components/scss/card.scss (~line 139): with the button at the offcanvas tier, an open offcanvas naturally paints over it.
    • yarn build to regenerate inst/components/dist/.
    • Update/extend tests covering full-screen stacking.
    • NEWS.md entry covering the stacking change and the new CSS custom properties.
  6. self-assigned this
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Priority: MediumValid bug or well-defined request with moderate impact or a workaround.ai-triage:doneMarks an issue whose AI triage workflow is complete.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions