Skip to content

Conversation

@elnelson575
Copy link
Contributor

@elnelson575 elnelson575 commented Nov 12, 2025

Fixes #1248

Adds buttons suitable for inclusion in toolbars.

Buttons:

  • Inherit font sizing from their toolbar parent element
  • Can have icons, text, or both
  • Default to no border, but can have a border
  • Can be deactivated or active
  • Check & format toolbar.R
  • Scss changes
  • Add tests
  • Example app
  • Regenerate docs + check

To-do:

  • Ensure that the toolbar doesn't change height based on button sizes, but that the buttons have a good default, legible size
  • Make sure there's no awkward gap between icon and label
  • Verify spacing between buttons is good
  • Fix footer
Example with active/disabled button

Before click activate button:
Screenshot 2025-11-24 at 10 12 37 AM

library(shiny)
library(bslib)

ui <- page_fillable(
  tags$head(
    tags$link(rel = "stylesheet", type = "text/css", href = "styles.css")
  ),
  card(
    card_header(
      icon("star"),
      "Card 1 header",
      toolbar(
        align = "right",
        toolbar_input_button(id = "see", icon = icon("eye")),
        toolbar_input_button(id = "save", icon = icon("save")),
        toolbar_input_button(id = "edit", icon = icon("pencil")),
        toolbar_input_button(
          id = "calendar",
          label = "Schedule",
          icon = icon("calendar"),
          disabled = TRUE
        )
      )
    ),
    p("Card 1 body"),
    actionButton("activate_schedule", "Activate Schedule"),
    max_height = "500px",
    card_footer(
      toolbar(
        align = "left",
        toolbar_input_button(id = "go", label = "Go"),
        toolbar_input_button(id = "Exit", label = "Exit")
      )
    )
  ),
  toolbar(
    align = "left",
    toolbar_input_button(
      id = "test2",
      icon = icon("star"),
      tooltip = "Favorite"
    ),
    toolbar_input_button(id = "love2", icon = icon("heart"), tooltip = "Like"),
    toolbar_input_button(
      id = "comment2",
      icon = icon("comment"),
      tooltip = "Comment"
    )
  ),
  card(
    card_header(
      "Card 2 header",
      toolbar(
        align = "right",
        downloadLink(
          "download2",
          "Download",
        )
      ),
    ),
    p("Card 2 body"),
    actionButton("activate_schedule2", "Activate Schedule"),
    max_height = "500px",
    card_footer(
      toolbar(
        align = "right",
        toolbar_input_button(
          id = "paragraph2",
          icon = icon("paragraph")
        )
      )
    )
  ),
  toolbar(
    align = "left",
    gap = "10",
    toolbar_input_button(id = "test", icon = icon("star")),
    toolbar_input_button(id = "love", icon = icon("heart")),
    toolbar_input_button(id = "comment", icon = icon("comment"))
  )
)

server <- function(input, output) {
  observeEvent(input$activate_schedule, {
    updateActionButton(
      inputId = "calendar",
      disabled = FALSE
    )
  })
}


shinyApp(ui = ui, server = server)

@elnelson575 elnelson575 linked an issue Nov 12, 2025 that may be closed by this pull request
elnelson575 and others added 2 commits November 21, 2025 09:08
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
rlang,
sass (>= 0.4.9)
sass (>= 0.4.9),
shiny (>= 1.11.1.9000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, shiny should stay under Suggests. You can just move this line back down to be between rmarkdown and testthat.

#' A toolbar which can contain buttons, inputs, and other UI elements in a small
#' form suitable for inclusion in card headers, footers, and other small places.
#'
#' @examplesIf rlang::is_interactive()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be @examples. We use this pattern when you wouldn't want to run the example unless you're in an interactive session -- like when you create a full Shiny app in the example. Showing a little snippet of HTML is generally safe (IIRC)

Comment on lines +10 to +12
#' toolbar_input_button(id = "see", icon = icon("eye")),
#' toolbar_input_button(id = "save", icon = icon("save")),
#' toolbar_input_button(id = "edit", icon = icon("pencil"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this example reminded me that I the current API doesn't do a great job of guiding people to fall into the pit of accessibility success.

It might be better to force people to provide either label or tooltip and then have a separate option like icon_only = TRUE. Then, if label is provided, we'd add an appropriate ARIA attribute. We should also evaluate the accessibility implications of using a tooltip to communicate meaning, maybe we'll end up always requiring label so we can set up the right ARIA attributes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this would also impact our determination of btn_type in toolbar_input_button()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So right now based on the Mac native voiceover functionality, here's what happens:
If label: reads label
If icon: reads the aria-label which is "icon_name icon" (ex. "calendar icon")
If tooltip: Reads the tooltip, then whatever case of the above applies.

Based on this, I actually think our implementation of tooltip might be more accessible than the non-tooltipped version.

Two potential options I'm thinking of:

  1. Require label always, set a show_label option to True or False which controls visibility. Label gets set as the aria attribute no matter what.
  2. Require a tooltip or a label, that gets set as the aria attribute.

Thoughts?

align-items: center;
align-self: stretch;
min-height: 2.5rem;
padding-block: 4px;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is likely the right final value, but I think we should see if we can hook this into a Bootstrap CSS variable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Toolbar: Toolbar Button

3 participants