shiny::downloadButton in bslib::card_header with icon instead of text

24 Views Asked by At

I wish to include a downloadButton on the right side of my bslib::card. Ideally, this would be an icon. What I have done so far is

require(shiny)
require(bslib)
require(ggplot2)

ui <- bslib::page_fillable(
    theme=bslib::bs_theme(version=5),
    title = "Card with Download Icon",
    bslib::card(
        bslib::card_header(
            class = "d-flex justify-content-between",
            "Card Title",
            shiny::downloadButton(
                outputId="download",
                label="",
                icon=shiny::icon("image") # way too large
            )
        ),
        shiny::plotOutput("the_plot")
    )
)

server <- function(input, output, session) {
    plot_obj <- shiny::reactive(
        ggplot2::qplot(Sepal.Length, Sepal.Width, data = iris)
    )
    output$the_plot <- shiny::renderPlot(plot_obj())
    output$download <- shiny::downloadHandler(
        filename = function() "card_snapshot.png",
        content = function(file) {
            ggplot2::ggsave(
                filename=file, plot=plot_obj(), device=png,
                width=16, height=9, units="cm", bg="white"
            )
        }
    )
}

shiny::shinyApp(ui, server)

but this results in a too large card header, i.e.

screenshot

I wonder how I can create a smaller icon for download?

I also tried shiny::downloadLink, but there seems to be not icon argument...

Any hint appreciated!

2

There are 2 best solutions below

0
SamR On BEST ANSWER

You're creating a button with outputId = "download", so you can add some css to your ui to select this element by ID (#download) and change the padding.

tags$head(
        tags$style(
            HTML("
                #download {
                    padding: 0px 5px;
                }")
        )
    )

Output

enter image description here

In this instance it's not actually necessary to wrap your css in htmltools::HTML(). However, it will become necessary if your style becomes more complicated and starts to use characters that you need to specify should not be escaped, like examples here which import fonts. I think it's good practice to use HTML() always when writing html or css in your R code, and then you don't have to think about whether you're using characters that might be escaped.

Complete ui code

ui <- bslib::page_fillable(
    tags$head(
        tags$style(
            HTML("
                #download {
                    padding: 0px 5px;
                }")
        )
    ),
    theme = bslib::bs_theme(version = 5),
    title = "Card with Download Icon",
    bslib::card(
        bslib::card_header(
            class = "d-flex justify-content-between",
            "Card Title",
            shiny::downloadButton(
                outputId = "download",
                label = "",
                icon = shiny::icon("image") # way too large
            )
        ),
        shiny::plotOutput("the_plot")
    )
)
0
Karsten W. On

Just for reference, I ended up with a downloadLink. I didn't know until now that the label can be anything, even an icon. So the card header that works for me is

bslib::card_header(
    class = "d-flex justify-content-between",
    "Card Title",
    shiny::downloadLink(
        outputId="download",
        label=bslib::tooltip(
            bsicons::bs_icon("file-earmark-image"),
            "Click to download Chart",
            placement = "right"
        )
    )
)