---
title: "Components"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Components}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
eval = FALSE
)
```
```{r}
library(shiny)
library(bootstrict)
```
This article covers the Bootstrap component library: cards, alerts, badges,
buttons, accordions, carousels, collapses, list groups, progress bars, spinners
and placeholders. Navigation components (nav/tabs, navbar, breadcrumb,
pagination, dropdown) have [their own article](navigation.html); overlays
(modal, offcanvas, toast, tooltips) are in [Overlays](overlays.html).
Some of these components are **interactive** — they report state as `input$id`
and are driven from the server with an `update_bs_*()` helper. Those follow the
same pattern throughout `bootstrict`; see [Overlays and server-driven
interactivity](overlays.html) for the full story.
## Buttons
`bs_button()` renders a Bootstrap button. It becomes a Shiny action button
**only when given an `id`** — then `input$id` is the click count, exactly like
`shiny::actionButton()`. Without an `id` it is an inert, styled button.
```{r}
bs_button(
id = NULL,
label = NULL,
...,
color = "primary", # a theme colour or "link"
outline = FALSE, # .btn-outline-*
size = NULL, # "sm" or "lg"
disabled = FALSE,
href = NULL, # set to render an styled as a button
type = "button", # "button"/"submit"/"reset"
class = NULL
)
```
```{r}
bs_button("go", "Go", color = "primary")
bs_button(label = "Cancel", color = "secondary", outline = TRUE)
```
Group buttons with `bs_button_group()` (add `vertical = TRUE` for a column), and
group groups with `bs_button_toolbar()`:
```{r}
bs_button_group(
bs_button(label = "Left"),
bs_button(label = "Right")
)
```
The standalone Bootstrap close button (used inside dismissible components) is
`bs_close_button()`. On a dark background use `white = TRUE`.
### Download buttons
`bs_download_button()` and `bs_download_link()` wrap the Shiny originals.
Shiny hardcodes the Bootstrap 3 class `.btn-default`, which has no Bootstrap 5
equivalent and leaves the button unstyled; these take `color` / `outline` /
`size` like `bs_button()` instead. The server side stays a plain
`shiny::downloadHandler()`.
```{r}
ui <- bs_page(
bs_container(bs_download_button("save", "Download CSV", color = "success"))
)
server <- function(input, output, session) {
output$save <- downloadHandler(
filename = "data.csv",
content = function(file) write.csv(mtcars, file)
)
}
```
`icon` defaults to `NULL` rather than Shiny's Font Awesome icon, which is
outside Bootstrap 5.
## Cards
Cards are built from composable pieces. `bs_card()` is the container; the rest
(`bs_card_header()`, `bs_card_body()`, `bs_card_title()`,
`bs_card_subtitle()`, `bs_card_text()`, `bs_card_footer()`, `bs_card_link()`)
map one-to-one to the Bootstrap card sub-elements.
```{r}
bs_card(
bs_card_header("Featured"),
bs_card_body(
bs_card_title("Card title"),
bs_card_subtitle("A subtitle"),
bs_card_text("Some quick example text to build on the card title."),
bs_card_link("Read more", href = "#")
),
bs_card_footer("Updated 3 mins ago")
)
```
`bs_card()` accepts `color=` (a background theme colour, `.text-bg-*`) and
`border=` (a border colour). For images, `bs_card_img()` places a picture at the
`"top"`, `"bottom"` or as an `"overlay"`; pair the overlay with
`bs_card_img_overlay()` to float text on top. `bs_card_group()` snaps several
cards into an equal-width attached grid.
```{r}
bs_card_group(
bs_card(bs_card_body("A")),
bs_card(bs_card_body("B"))
)
```
## Alerts
`bs_alert()` is a coloured message box. `dismissible = TRUE` adds a close button
and fade-out.
```{r}
bs_alert("Well done! You read this important message.", color = "success")
bs_alert("Heads up — check your settings.", color = "warning", dismissible = TRUE)
```
Inside an alert, `bs_alert_heading()` gives a matched heading and
`bs_alert_link()` a colour-matched link:
```{r}
bs_alert(
color = "danger",
bs_alert_heading("Something went wrong"),
"Read the ", bs_alert_link("full log", href = "#"), " for details."
)
```
Give it an `id` and it becomes interactive: `input$id` is `TRUE` while the
alert is on the page and `FALSE` once dismissed, and `close_bs_alert()`
dismisses it from the server. Bootstrap removes the element, so an alert
cannot be brought back — render it from a `renderUI()` if it has to come and
go.
```{r}
ui <- bs_page(
bs_container(
bs_alert("Saved.", id = "saved", color = "success", dismissible = TRUE),
bs_button("dismiss", "Dismiss")
)
)
server <- function(input, output, session) {
observeEvent(input$dismiss, close_bs_alert("saved"))
observe(message("alert still shown: ", input$saved))
}
```
## Badges
Small count/label pills:
```{r}
bs_badge("New", color = "success")
bs_badge("42", color = "danger", pill = TRUE)
```
## Accordion (interactive)
A vertically collapsing set of panels. The value(s) of the open panel(s) are
reported as `input$id`, and you open/close them from the server with
`update_bs_accordion()`.
```{r}
bs_accordion(
"acc",
bs_accordion_panel("First", "Panel one body", value = "one"),
bs_accordion_panel("Second", "Panel two body", value = "two"),
open = "one"
)
```
- `open` accepts panel value(s), or `TRUE` (open all — only sensible with
`multiple = TRUE`), or `FALSE`/`NULL` (none).
- `multiple = TRUE` lets panels stay open independently ("always open").
- `flush = TRUE` renders edge-to-edge.
```{r}
server <- function(input, output, session) {
observe(print(input$acc)) # value(s) of open panel(s)
observeEvent(input$go, update_bs_accordion("acc", open = "two"))
}
```
## Carousel (interactive)
A slideshow of `bs_carousel_item()`s. The 0-based index of the active slide is
reported as `input$id`; drive it with `update_bs_carousel()`.
```{r}
bs_carousel(
"demo",
bs_carousel_item(bs_img("1.jpg"), active = TRUE, caption = "First slide"),
bs_carousel_item(bs_img("2.jpg"))
)
```
- `indicators` / `controls` toggle the clickable dots and prev/next arrows.
- `fade = TRUE` crossfades; `autoplay = TRUE` (default) auto-cycles;
`interval` sets the cycle time in ms.
- Exactly one item is `active` (the first is defaulted if you set none).
```{r}
update_bs_carousel("demo", to = 2) # jump to a slide (0-based)
update_bs_carousel("demo", slide = "next")
```
## Collapse (interactive)
A container that shows/hides content. Its state is reported as `input$id`
(`TRUE` when visible). Toggle it from the UI with `bs_collapse_trigger()` (no
server round trip) or from the server with `update_bs_collapse()`.
```{r}
tagList(
bs_collapse_trigger("more", "Toggle details"),
bs_collapse("more", "Hidden content revealed on toggle.")
)
```
```{r}
update_bs_collapse("more", "show") # "toggle" (default), "show" or "hide"
```
## List group (interactive)
A flexible list that becomes **server-selectable** when you give it an `id`:
the active item's `value` is reported as `input$id`, and
`update_bs_list_group()` activates an item by value.
```{r}
bs_list_group(
"picker",
bs_list_group_item("An item", value = "a", action = TRUE),
bs_list_group_item("A second item", value = "b", action = TRUE)
)
```
Items can be plain (``), actionable (`action = TRUE` → a `