rshinyquartobslib

How to make value boxes rendered via renderUI() not appear stacked vertically?


I'm building a Quarto dashboard with format: dashboard and server: shiny. I'm comparing value boxes that are:

written directly in the UI, versus created dynamically using renderUI() in the server

The UI-based value boxes appear side-by-side as expected. But the server-rendered ones appear stacked vertically, even though they're intended to share the same layout height.

Is there a known layout limitation for uiOutput() in format: dashboard? Is there a workaround that allows multiple server-rendered value boxes to appear side-by-side like those defined in the UI?

Background: I need to use renderUI() because I'm developing a multi-language app using shiny.i18n, and only server-side rendering allows dynamic UI elements like value_box() to update correctly when the language is changed.

Here is MRE:

---
title: "Value Box Layout Comparison"
format:
  dashboard:
    orientation: columns
    page-navigation: true
    page-navigation-id: site_nav
server: shiny
---

```{r}
#| context: setup
library(shiny)
library(bslib)
```

## Sidebar {.sidebar}

Nothing here — just a comparison between UI and server-based value boxes.


## Value Boxes directly in UI

### Three value boxes side-by-side {height="40%"}

```{r}
value_box(
  title = "Box UI 1",
  value = 42,
  theme = "primary"
)

value_box(
  title = "Box UI 2",
  value = 58,
  theme = "primary"
)

value_box(
  title = "Box UI 3",
  value = 68,
  theme = "primary"
)
```
### Three value boxes side-by-side {height="60%"}
```{r}
#| component: input
#| title: Just space
cat("Just space")
```


## Value Boxes rendered from server

### Three value boxes via `renderUI()` {height="40%"}

```{r}
#| title: Value Boxes rendered from server

uiOutput("box_server_1")
uiOutput("box_server_2")
uiOutput("box_server_3")
```

### Three value boxes side-by-side {height="60%"}
```{r}
#| component: input
#| title: Just space
cat("Just space")
```

```{r}
#| context: server

output$box_server_1 <- renderUI({
  value_box(
    title = "Box Server 1",
    value = 123,
    theme = "danger"
  )
})

output$box_server_2 <- renderUI({
  value_box(
    title = "Box Server 2",
    value = 321,
    theme = "danger"
  )
})

output$box_server_3 <- renderUI({
  value_box(
    title = "Box Server 3",
    value = 456,
    theme = "danger"
  )
})
```

enter image description here

Desired output: The blue value boxes with renderUI. Many thanks.


Solution

  • Shiny does not automatically arrange the elements inside a grid. To do this, you can use bslib's layout_column_wrap():

    layout_column_wrap(
      width = 1/3,
      uiOutput("box_server_1"),
      uiOutput("box_server_2"),
      uiOutput("box_server_3"),
    )
    

    enter image description here

    However, this seems to let the title of the card disappear. You can keep if it you define the card explicitly:

    ::: {.card title="Value Boxes rendered from server"}
    ```{r}
    layout_column_wrap(
      width = 1/3,
      uiOutput("box_server_1"),
      uiOutput("box_server_2"),
      uiOutput("box_server_3"),
    )
    ```
    :::
    

    enter image description here