diff --git a/.gitignore b/.gitignore
index d323a105e..adcb040ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,10 +19,6 @@ inst/yarn.lock
inst/rmarkdown/templates/*/skeleton/skeleton.html
-vignettes/navbar-global
-vignettes/navbar-global-fillable
-vignettes/navbar-local-scroll
-vignettes/navbar-local-fill
-vignettes/page-scroll
-vignettes/page-fill
-vignettes/page-fill-double
+vignettes/*.html
+# rendered examples that appear in iframes
+vignettes/examples
diff --git a/DESCRIPTION b/DESCRIPTION
index ee13faf41..5b96ac9fb 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -90,13 +90,16 @@ Config/Needs/website:
crosstalk,
dplyr,
DT,
+ ggplot2,
glue,
htmlwidgets,
leaflet,
+ lorem,
plotly,
purrr,
rprojroot,
rstudio/htmltools,
+ scales,
stringr,
tidyr
Config/Needs/deploy:
diff --git a/NEWS.md b/NEWS.md
index f55fb3be1..91df56f79 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -45,7 +45,7 @@ Although `{bslib}` is still maturing, and will continue to receiving new UI feat
* https://rstudio.github.io/bslib/articles/cards.html
* https://rstudio.github.io/bslib/articles/value-boxes.html
- * https://rstudio.github.io/bslib/articles/layouts.html
+ * https://rstudio.github.io/bslib/articles/column-layout.html
# bslib 0.4.1
diff --git a/README.Rmd b/README.Rmd
index f7b808185..890cffc38 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -22,14 +22,14 @@ library(bslib)
# bslib
-The `bslib` R package provides tools for customizing [Bootstrap themes](https://getbootstrap.com/docs/4.6/getting-started/theming/) directly from R, making it much easier to customize the appearance of [Shiny](https://shiny.rstudio.com/) apps & [R Markdown](https://rmarkdown.rstudio.com/) documents. `bslib`'s primary goals are:
+The `bslib` R package provides a modern UI toolkit for [Shiny](https://shiny.rstudio.com/) and [R Markdown](https://rmarkdown.rstudio.com/) based on [Bootstrap](https://getbootstrap.com/). `bslib`'s primary goals are:
+* Provide modern UI components, such as [cards](https://rstudio.github.io/bslib/articles/cards.html), [sidebars](https://rstudio.github.io/bslib/articles/sidebars.html), [value boxes](https://rstudio.github.io/bslib/articles/value-boxes.html), [layouts](https://rstudio.github.io/bslib/articles/column-layout.html), and more.
* Make [custom theming](https://rstudio.github.io/bslib/articles/bslib.html#custom) as easy as possible.
* Custom themes may even be created interactively in [real-time](https://rstudio.github.io/bslib/articles/bslib.html#real-time).
* Also provide easy access to pre-packaged [Bootswatch themes](https://rstudio.github.io/bslib/articles/bslib.html#bootswatch).
-* Make [upgrading from Bootstrap 3 to 4 (and beyond)](https://rstudio.github.io/bslib/articles/bslib.html#versions) as seamless as possible.
- * Shiny and R Markdown default to Bootstrap 3 and will continue to do so to avoid breaking legacy code.
-* Provide useful wrappers around modern Bootstrap (and CSS) components, such as [cards](https://rstudio.github.io/bslib/articles/cards.html), [value boxes](https://rstudio.github.io/bslib/articles/value-boxes.html), [layouts](https://rstudio.github.io/bslib/articles/layouts.html), and more.
+* Make it seamless to use any version of [Bootstrap](https://rstudio.github.io/bslib/articles/bslib.html#versions).
+ * Shiny and R Markdown currently default to Bootstrap 3 and may continue to do so to avoid breaking legacy code.
* Serve as a general foundation for Shiny and R Markdown extension packages.
* Extensions such as [`flexdashboard`](https://flexdashboard-pkg.netlify.app/articles/theme.html), [`pkgdown`](https://pkgdown.r-lib.org/dev/articles/customise.html), and [`bookdown`](https://pkgs.rstudio.com/bookdown/reference/bs4_book.html) already fully support [`bslib`'s custom theming capabilities](https://rstudio.github.io/bslib/articles/bslib.html#custom).
@@ -55,19 +55,32 @@ install.packages("rmarkdown")
## Basic usage {#usage}
-`bslib` is designed for use with any Shiny or R Markdown project that uses Bootstrap. In most cases, you can identify a project that uses Bootstrap when the relevant page constructor has a `theme` parameter. For example, most Shiny page layout functions (e.g., `shiny::navbarPage()`) and some popular R Markdown formats (e.g., `rmarkdown::html_document`) all have a `theme` parameter.
+### Shiny
-To use `bslib` in Shiny, provide a `bs_theme()` _object_ to the `theme` parameter; and in R Markdown, provide `bs_theme()` _parameters_ to `theme`. For example, here's a way to upgrade Shiny (left) and R Markdown (right) from Bootstrap 3 to 5:
+To get started using `bslib` in Shiny, use one of its `page_*()` functions. These drop-in replacements for `shiny::*Page()` updates the page to use the latest supported version Bootstrap.
+
+```r
+ui <- page_fluid(
+ h2("Hello world")
+)
+shinyApp(ui, function(...) {})
+```
+
+In production, it's recommended to pin the version of Bootstrap (currently 5) via `bs_theme()`. As you'll learn in [getting started](https://rstudio.github.io/bslib/articles/bslib.html), `bs_theme()` also makes it easy to theme the app by customizing (and/or adding to) Bootstrap CSS.
-
```r
library(shiny)
-ui <- navbarPage(
+ui <- page_fixed(
theme = bs_theme(version = 5),
- ...
+ h2("Hello world")
)
shinyApp(ui, function(...) {})
```
+
+### R Markdown
+
+To get started using `bslib` in R Markdown (and compatible extensions like [`flexdashboard`](https://flexdashboard-pkg.netlify.app/articles/theme.html)), provide `bs_theme()` parameters to the `theme` parameter of the output format. For example, here's how to use "stock" Bootstrap 5 with `rmarkdown::html_document`:
+
```r
---
output:
@@ -76,16 +89,18 @@ output:
version: 5
---
```
-
-
-See the [Get Started](https://rstudio.github.io/bslib/articles/bslib.html) article to learn more about Bootstrap versions, pre-packaged Bootswatch themes, (real-time) custom theming, and more.
-To get started more quickly, choose a relevant R Markdown template from inside RStudio by going to File -> New File -> R Markdown -> From Template:
+`bslib` also provides some R Markdown templates that can be accessed from RStudio by going to File -> New File -> R Markdown -> From Template:
```{r, echo = FALSE, out.width="60%"}
knitr::include_graphics("man/figures/rstudio-templates.png")
```
+### pkgdown
+
+`{pkgdown}` has its way of using `bslib`, see
+
+
## Getting help
There are two main places to get help with `bslib`:
diff --git a/README.md b/README.md
index 9eba86412..5a3730f5c 100644
--- a/README.md
+++ b/README.md
@@ -12,13 +12,18 @@ status](https://github.com/rstudio/bslib/actions/workflows/R-CMD-check.yaml/badg
# bslib
-The `bslib` R package provides tools for customizing [Bootstrap
-themes](https://getbootstrap.com/docs/4.6/getting-started/theming/)
-directly from R, making it much easier to customize the appearance of
-[Shiny](https://shiny.rstudio.com/) apps & [R
-Markdown](https://rmarkdown.rstudio.com/) documents. `bslib`’s primary
-goals are:
-
+The `bslib` R package provides a modern UI toolkit for
+[Shiny](https://shiny.rstudio.com/) and [R
+Markdown](https://rmarkdown.rstudio.com/) based on
+[Bootstrap](https://getbootstrap.com/). `bslib`’s primary goals are:
+
+ - Provide modern UI components, such as
+ [cards](https://rstudio.github.io/bslib/articles/cards.html),
+ [sidebars](https://rstudio.github.io/bslib/articles/sidebars.html),
+ [value
+ boxes](https://rstudio.github.io/bslib/articles/value-boxes.html),
+ [layouts](https://rstudio.github.io/bslib/articles/column-layout.html),
+ and more.
- Make [custom
theming](https://rstudio.github.io/bslib/articles/bslib.html#custom)
as easy as possible.
@@ -26,17 +31,10 @@ goals are:
[real-time](https://rstudio.github.io/bslib/articles/bslib.html#real-time).
- Also provide easy access to pre-packaged [Bootswatch
themes](https://rstudio.github.io/bslib/articles/bslib.html#bootswatch).
- - Make [upgrading from Bootstrap 3 to 4 (and
- beyond)](https://rstudio.github.io/bslib/articles/bslib.html#versions)
- as seamless as possible.
- - Shiny and R Markdown default to Bootstrap 3 and will continue to
- do so to avoid breaking legacy code.
- - Provide useful wrappers around modern Bootstrap (and CSS)
- components, such as
- [cards](https://rstudio.github.io/bslib/articles/cards.html), [value
- boxes](https://rstudio.github.io/bslib/articles/value-boxes.html),
- [layouts](https://rstudio.github.io/bslib/articles/layouts.html),
- and more.
+ - Make it seamless to use any version of
+ [Bootstrap](https://rstudio.github.io/bslib/articles/bslib.html#versions).
+ - Shiny and R Markdown currently default to Bootstrap 3 and may
+ continue to do so to avoid breaking legacy code.
- Serve as a general foundation for Shiny and R Markdown extension
packages.
- Extensions such as
@@ -69,29 +67,43 @@ install.packages("rmarkdown")
## Basic usage
-`bslib` is designed for use with any Shiny or R Markdown project that
-uses Bootstrap. In most cases, you can identify a project that uses
-Bootstrap when the relevant page constructor has a `theme` parameter.
-For example, most Shiny page layout functions (e.g.,
-`shiny::navbarPage()`) and some popular R Markdown formats (e.g.,
-`rmarkdown::html_document`) all have a `theme` parameter.
+### Shiny
+
+To get started using `bslib` in Shiny, use one of its `page_*()`
+functions. These drop-in replacements for `shiny::*Page()` updates the
+page to use the latest supported version Bootstrap.
-To use `bslib` in Shiny, provide a `bs_theme()` *object* to the `theme`
-parameter; and in R Markdown, provide `bs_theme()` *parameters* to
-`theme`. For example, here’s a way to upgrade Shiny (left) and R
-Markdown (right) from Bootstrap 3 to 5:
+``` r
+ui <- page_fluid(
+ h2("Hello world")
+)
+shinyApp(ui, function(...) {})
+```
-
+In production, it’s recommended to pin the version of Bootstrap
+(currently 5) via `bs_theme()`. As you’ll learn in [getting
+started](https://rstudio.github.io/bslib/articles/bslib.html),
+`bs_theme()` also makes it easy to theme the app by customizing (and/or
+adding to) Bootstrap CSS.
``` r
library(shiny)
-ui <- navbarPage(
+ui <- page_fixed(
theme = bs_theme(version = 5),
- ...
+ h2("Hello world")
)
shinyApp(ui, function(...) {})
```
+### R Markdown
+
+To get started using `bslib` in R Markdown (and compatible extensions
+like
+[`flexdashboard`](https://flexdashboard-pkg.netlify.app/articles/theme.html)),
+provide `bs_theme()` parameters to the `theme` parameter of the output
+format. For example, here’s how to use “stock” Bootstrap 5 with
+`rmarkdown::html_document`:
+
``` r
---
output:
@@ -101,19 +113,17 @@ output:
---
```
-
-
-See the [Get
-Started](https://rstudio.github.io/bslib/articles/bslib.html) article to
-learn more about Bootstrap versions, pre-packaged Bootswatch themes,
-(real-time) custom theming, and more.
-
-To get started more quickly, choose a relevant R Markdown template from
-inside RStudio by going to File -\> New File -\> R Markdown -\> From
+`bslib` also provides some R Markdown templates that can be accessed
+from RStudio by going to File -\> New File -\> R Markdown -\> From
Template:
+### pkgdown
+
+`{pkgdown}` has its way of using `bslib`, see
+
+
## Getting help
There are two main places to get help with `bslib`:
diff --git a/_pkgdown.yml b/_pkgdown.yml
index 6ef775561..f350dfdd0 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -10,7 +10,7 @@ template:
bslib:
info: "#E6F2FD"
base_font:
- google: "Atkinson Hyperlegible"
+ google: {family: "Atkinson Hyperlegible", wght: [300, 400, 700], ital: [0, 1]}
headings-color: "#206B72"
link-color: "#216B73"
link-decoration: underline var(--bs-info) dotted
@@ -24,29 +24,38 @@ navbar:
bg: info
type: light
structure:
- left: [intro, articles, integration]
+ left: [intro, theming, components, layouts]
right: [reference, news, github]
components:
home: ~
- articles:
- text: Articles
+ theming:
+ text: Theming
menu:
- #- text: Why Sass over CSS?
- # href: articles/why-sass.html
- - text: Cards
- href: articles/cards.html
- - text: Value Boxes
- href: articles/value-boxes.html
- - text: Sidebars
- href: articles/sidebars.html
- - text: Layouts
- href: articles/layouts.html
- text: Theming variables
href: articles/bs5-variables.html
- text: Utility Classes
href: articles/utility-classes.html
- text: Custom components
href: articles/custom-components.html
+ components:
+ text: Components
+ menu:
+ - text: Cards
+ href: articles/cards.html
+ - text: Sidebars
+ href: articles/sidebars.html
+ - text: Value Boxes
+ href: articles/value-boxes.html
+ layouts:
+ text: Layouts
+ menu:
+ - text: Column-based layout
+ href: articles/column-layout.html
+ - text: Filling layouts
+ href: articles/filling.html
+ - text: Multi page/tab
+ href: https://rstudio.github.io/bslib/reference/navs.html#details
+
reference:
text: Reference
href: reference/index.html
@@ -131,3 +140,10 @@ reference:
- theme_bootswatch
- bootswatch_themes
- version_default
+
+
+ redirects:
+ - ["articles/cards.html#fixed-sizing", "articles/cards.html#scrolling-contents"]
+ - ["articles/cards.html#responsive-sizing", "articles/cards.html#filling-contents"]
+ - ["articles/cards.html#fixed-responsive-sizing", "articles/cards.html#scrolling-filling"]
+ - ["articles/cards.html#dynamic-rendering-shiny", "articles/cards.html#shiny"]
diff --git a/pkgdown/extra.css b/pkgdown/extra.css
index c0652cb61..75fe77ea4 100644
--- a/pkgdown/extra.css
+++ b/pkgdown/extra.css
@@ -23,3 +23,68 @@ a:focus, a:hover {
table.dataTable.table-bordered {
border-collapse: collapse !important;
}
+
+main h2 {
+ margin-top: 1lh;
+}
+
+.html-widget {
+ margin-bottom: 0;
+}
+
+/* ---- Callouts ---- */
+.callout {
+ position: relative;
+ border: 1px solid gray;
+ padding: 1rem;
+ margin: 1rem 0;
+ border-radius: var(--bs-border-radius);
+}
+
+.callout > :last-child {
+ margin-bottom: 0;
+}
+
+.callout > h3 {
+ position: relative;
+ margin: -1rem;
+ margin-bottom: 10px;
+ padding: 1rem;
+ font-size: 1.5rem;
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+
+.callout > h3 > .anchor {
+ display: none;
+}
+
+.callout.callout-warning {
+ border-color: gold
+}
+
+.callout.callout-warning > h3 {
+ color: #473D00;
+ background-color: hsl(51 100% 94% / 1);
+}
+
+.callout.callout-warning > h3:before {
+ /* https://icons.getbootstrap.com/icons/exclamation-diamond-fill/ */
+ content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16px' height='16px' fill='%23473D00' class='bi bi-exclamation-diamond-fill' viewBox='0 0 16 16'%3E%3Cpath d='M9.05.435c-.58-.58-1.52-.58-2.1 0L.436 6.95c-.58.58-.58 1.519 0 2.098l6.516 6.516c.58.58 1.519.58 2.098 0l6.516-6.516c.58-.58.58-1.519 0-2.098L9.05.435zM8 4c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995A.905.905 0 0 1 8 4zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z'/%3E%3C/svg%3E");
+ margin-right: 4px
+}
+
+.callout.callout-note {
+ border-color: #bdccdc;
+}
+
+.callout.callout-note > h3 {
+ color: #373a3c;
+ background-color: #e9f2fc;
+}
+
+.callout.callout-note > h3:before {
+ /* https://icons.getbootstrap.com/icons/info-circle/ */
+ content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16px' height='16px' fill='%232780e3' class='bi bi-exclamation-diamond-fill' viewBox='0 0 16 16'%3E%3Cpath d='M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z'/%3E%3C/svg%3E");
+ margin-right: 4px
+}
diff --git a/vignettes/cards.Rmd b/vignettes/cards.Rmd
index a39bf89e4..5d9f653b7 100644
--- a/vignettes/cards.Rmd
+++ b/vignettes/cards.Rmd
@@ -6,50 +6,21 @@ resource_files:
Cards are a common organizing unit for modern user interfaces (UI). At their core, they're just rectangular containers with borders and padding. However, when utilized properly to group related information, they help users better digest, engage, and navigate through content. This is why most successful dashboard/UI frameworks make cards a core feature of their component library. This article provides an overview of the API that bslib provides to create [Bootstrap cards](https://getbootstrap.com/docs/5.0/components/card/).
-One major feature that bslib adds to Bootstrap cards is the ability to expand the card to a [full screen view](#responsive-sizing). Often this feature wants [output that resizes itself to fit its card container](#responsive-sizing). To do this as advertised, make sure you have the latest version of shiny and htmlwidgets:
+## Setup code
-```r
-install.packages("shiny")
-install.packages("htmlwidgets")
-```
-
-Since this article is statically hosted (i.e., not powered by Shiny), it uses statically rendered [htmlwidgets](http://www.htmlwidgets.org/) like `{plotly}` and `{leaflet}` (but don't worry, `card()`s [work in Shiny equally as well](#dynamic-rendering-shiny)). Here's some code to create those widgets:
+To demonstrate that bslib cards work outside of Shiny (i.e., in R Markdown, static HTML, etc), we'll make repeated use of statically rendered [htmlwidgets](http://www.htmlwidgets.org/) like `{plotly}` and `{leaflet}`. Here's some code to create those widgets:
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
-lorem_ipsum_dolor_sit_amet <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Id nibh tortor id aliquet lectus proin nibh nisl. Adipiscing at in tellus integer feugiat. Arcu bibendum at varius vel pharetra vel turpis nunc eget. Cursus sit amet dictum sit amet justo. Sit amet consectetur adipiscing elit. Vestibulum mattis ullamcorper velit sed ullamcorper. Enim facilisis gravida neque convallis a. Elit duis tristique sollicitudin nibh sit amet. Magna eget est lorem ipsum. Gravida dictum fusce ut placerat orci nulla pellentesque dignissim. Mauris in aliquam sem fringilla ut morbi. Id semper risus in hendrerit gravida rutrum quisque non tellus. At erat pellentesque adipiscing commodo elit at imperdiet dui. Fames ac turpis egestas maecenas pharetra convallis posuere morbi. Duis convallis convallis tellus id interdum velit laoreet id. Aliquet lectus proin nibh nisl. Nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis. Bibendum enim facilisis gravida neque convallis a."
-
# pkgdown really wants BS5+ markup for tabs, and this is currently the best way to achieving that :(
# (note this isn't a problem for any format based on html_document_base)
shiny:::setCurrentTheme(bslib::bs_theme())
```
```{scss, echo = FALSE}
-/* Credit to https://getcssscan.com/css-box-shadow-examples */
-.card {
- box-shadow:
- rgba(0, 0, 0, 0.25) 0px 54px 55px,
- rgba(0, 0, 0, 0.12) 0px -12px 30px,
- rgba(0, 0, 0, 0.12) 0px 4px 6px,
- rgba(0, 0, 0, 0.17) 0px 12px 13px,
- rgba(0, 0, 0, 0.09) 0px -3px 5px;
- margin-bottom: 3rem;
-}
-
-.bslib-grid-layout .card {
- box-shadow: none;
- margin-bottom: 0rem;
-}
-
-.bslib-value-box.card {
- box-shadow: none;
- margin-bottom: 0rem;
- color: white !important;
-}
-
.section.level2 {
- margin-top: 5rem;
+ margin-top: 3rem;
}
```
@@ -68,16 +39,25 @@ plotly_widget <- plot_ly(x = diamonds$cut) %>%
config(displayModeBar = FALSE) %>%
layout(margin = list(t = 0, b = 0, l = 0, r = 0))
-leaflet_widget <- leaflet() %>%
+leaflet_widget <- leafletOptions(attributionControl = FALSE) %>%
+ leaflet(options = .) %>%
addTiles()
```
+::: {.callout .callout-note}
+
Shiny usage
+
+Cards work equally well [in Shiny](#shiny). In the examples below, replace `plotly_widget` with `plotlyOutput()` and `leaflet_widget` with `leafletOutput()` to adapt them for Shiny server-rendered plots/maps.
+:::
+
+
+
## Hello `card()`
-::: row
+::: {.row .mt-3}
::: col-md-6
-A `card()` is designed to handle any number of "known" card items (e.g., `card_header()`, `card_body()`, etc) as unnamed arguments (i.e., children). As we'll see shotly, `card()` also has some useful named arguments (e.g., `full_screen`, `height`, etc).
+A `card()` is designed to handle any number of "known" card items (e.g., `card_header()`, `card_body()`, etc) as unnamed arguments (i.e., children). As we'll see shortly, `card()` also has some useful named arguments (e.g., `full_screen`, `height`, etc).
At their core, `card()` and card items are just an HTML `div()` with a special Bootstrap class, so you can use Bootstrap's utility classes to customize things like [colors](https://getbootstrap.com/docs/5.2/utilities/background/), [text](https://getbootstrap.com/docs/5.2/utilities/text/), [borders](https://getbootstrap.com/docs/5.2/utilities/borders), etc.
:::
@@ -99,7 +79,7 @@ card(
## Implicit `card_body()`
-::: row
+::: {.row .mt-3}
::: col-md-6
If you find yourself using `card_body()` without changing any of its defaults, consider dropping it altogether since any direct children of `card()` that aren't "known" `card()` items, are wrapped together into an implicit `card_body()` call.[^1] For example, the code to the right generates HTML that is identical to the previous example:
:::
@@ -113,394 +93,437 @@ card(
class = "bg-dark",
"A header"
),
- markdown("Some text with a [link](https://github.com)")
+ markdown("Some text with a [link](https://github.com).")
)
```
:::
:::
-## Fixed sizing
+## Restricting growth
-::: row
+::: {.row .mt-3}
::: col-md-6
-By default, a `card()`'s size grows to accommodate the size of it's contents. Thus, if some portion of the `card_body()` contains a large amount of text, table(s), etc., consider setting a fixed `height`. And in that case, if the contents exceed the specified height, they'll be scrollable.
+By default, a `card()`'s size grows to accommodate the size of it's contents. Thus, if a `card_body()` contains a large amount of text, tables, etc., you may want to specify a `height` or `max_height`. That said, when laying out [multiple cards](#multiple-cards), it's likely best not to specify height on the `card()`, and instead, let the layout determine the height `layout_column_wrap()`.
+
+Although scrolling is convenient for reducing the amount of space required to park lots of content, it can also be a nuisance to the user. To help reduce the need for scrolling, consider pairing scrolling with `full_screen = TRUE` (which adds an icon to expand the card's size to the browser window). Notice how, when the card is expanded to full-screen, `max_height`/`height` won't effect the full-screen size of the card.
:::
::: col-md-6
```{r}
card(
+ max_height = 250,
+ full_screen = TRUE,
card_header(
"A long, scrolling, description"
),
- card_body(
- height = 150,
- lorem_ipsum_dolor_sit_amet
- )
+ lorem::ipsum(paragraphs = 3, sentences = 5)
)
```
:::
:::
-::: row
+
+## Filling outputs
+
+::: {.row .mt-3}
::: col-md-6
-Alternatively, you can also set the `height` of the card to a fixed size and set `fill = TRUE` to have the `card_body()` container shrink/grow to fit the available space in a `card()`. Note that, by doing this, the _children_ of the `card_body()` aren't necessarily allowed to shrink/grow to fit the `card_body()`, which `card_body_fill()` (aka "[responsize sizing](#responsize-sizing)") is designed to do.
+A `card()`'s default behavior is optimized for facilitating [filling layouts](filling.html). More specifically, if a **fill item** (e.g., `plotly_widget`), appears as a _direct child_ of a `card_body()`, it resizes to fit the `card()`s specified height. This means, by specifying `height = 250` we've effectively shrunk the plot's height from its default of 400 down to about 200 pixels. And, when expanded to `full_screen`, the plot grows to match the `card()`'s new size.
:::
::: col-md-6
```{r}
card(
- height = 200,
- card_header(
- "A long, scrolling, description"
- ),
- card_body(
- fill = TRUE,
- lorem_ipsum_dolor_sit_amet
- )
+ height = 250,
+ full_screen = TRUE,
+ card_header("A filling plot"),
+ card_body(plotly_widget)
)
```
:::
:::
+::: {.row .mt-5}
+::: col-md-6
+Most htmlwidgets (e.g., plotly, leaflet, etc) and some other Shiny output bindings (e.g, `plotOutput()`, `imageOutput()`, etc) are **fill item**s by default, so this behavior "just works" in those scenarios. And, in some of these situations, it's helpful to remove `card_body()`'s padding, which can be done via [spacing & alignment utility classes](#spacing-alignment).
+:::
-## Responsive sizing
-
-
-
-
-Unlike `card_body()`, `card_body_fill()` encourages its children to grow and shrink vertically as needed in response to its `card()`'s height. Responsive sizing is particularly useful for `card(full_screen = TRUE, ...)`, which adds an icon (displayed on hover) to expand the `card()` to a full screen view.
-
-Since many htmlwidgets (like `plotly::plot_ly()`) and Shiny output bindings (like `shiny::plotOutput()`) default to a fixed height of 400 pixels, but are actually capable of responsive sizing, you'll get a better result with `card_body_fill()` instead of `card_body()` in these cases (compare the "Responsive" with the "Fixed" result using the tabs to the right).
-
-
+:::
+:::
-::: row
+
+::: {.row .mt-5}
::: col-md-6
-Under-the-hood, `card_body_fill()` achieves its behavior because it is a [flex container](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), which makes its direct children flex items. This can lead to suprising, yet useful, differences in behavior from `card_body()`. For example, each inline element (like text, `actionLink()`, `actionButton()`, etc) is placed in a new row and stretches horizontally (as shown in the example). In the case where you want particular elements inside of `card_body_fill()` to behave as though they're in `card_body()` (i.e., have the `actionLink()` and `actionButton()` appear inline on the same line), just wrap those elements in a `div()`.
+**Fill item**(s) aren't limited in how much they grow and shrink, which can be problematic when a card becomes very small. To work around this, consider adding a `min_height` on the `card_body()` container. For example, try using the handle on the lower-right portion of this card example to make the card taller/smaller.
+
+This interactive example is a bit contrived in that we're using [CSS resize](https://developer.mozilla.org/en-US/docs/Web/CSS/resize) to demonstrate how to make plots that don't shrink beyond a certain point, but this concept becomes quite useful when implementing page-level [filling layouts](filling.html) (i.e., `page_fillable()`) with [multiple cards](#multiple-cards).
:::
::: col-md-6
```{r}
card(
- height = 250, full_screen = TRUE,
- card_header("A plot with an action links"),
- card_body_fill(
+ height = 300,
+ style = "resize:vertical;",
+ card_header("Plots that grow but don't shrink"),
+ card_body(
+ min_height = 250,
plotly_widget,
- actionLink(
- "go", "Action link",
- class = "link-primary align-self-center"
- ),
- actionButton(
- "go_btn", "Action button",
- class = "btn-primary rounded-0"
- )
+ plotly_widget
)
)
```
:::
:::
+::: {.callout .callout-warning}
+
Troubleshooting fill
-::: row
-::: col-md-6
-Sometimes it's useful to put a limit on how much the contents of `card_body_fill()` may grow or shrink. For example, here's a case where the plot won't expand over 400 pixels (try expanding to full screen).
+As you'll learn more about in [filling layouts](filling.html), a **fill item** loses its ability to fill when wrapped in additional UI element that isn't a **fillable** container. To fix the situation, use `as_fill_carrier()` to allow the additional element to carry the potential to fill from the `card_body()` down to the fill item.
:::
+
+## Multiple `card_body()`
+
+A `card()` can have multiple `card_body()`s, which is especially useful for:
+
+1. Combining both resizable and non-resizable contents (i.e., **fill items** and non-fill).
+2. Allowing each `card_body()` to have their own styling (via inline styles and/or utility classes) and resizing limits (e.g., `min_height`).
+
+For example, when pairing filling output with scrolling content, you may want `min_height` on the filling output since the scrolling content will force it to shrink:
+
+::: {.row .mt-3}
::: col-md-6
-```{r}
+```{r multi-card-body, eval = FALSE}
card(
- height = 200, full_screen = TRUE,
- card_header("Try expanding full screen"),
- card_body_fill(
- plotly_widget,
- max_height = "400px"
+ height = 375,
+ full_screen = TRUE,
+ card_header(
+ "Filling plot, scrolling description"
+ ),
+ card_body(
+ min_height = 200,
+ plotly_widget
+ ),
+ card_body(
+ class = "lead container",
+ lorem::ipsum(paragraphs = 10, sentences = 5)
)
)
```
:::
+
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="multi-card-body", echo=FALSE}
+```
+:::
:::
-## Fixed & responsive sizing
+::: {.row .mt-5}
-::: row
-::: col-md-6
-Sometimes it's desirable to combine both `card_body_fill()` with `card_body()` to allow some portion of the body to grow/shrink as needed, but also keep another portion at a fixed/defined height.
-:::
+Also, when the content has a fixed size, and should not be allowed to scroll, set `fill = FALSE`:
::: col-md-6
-```{r}
+```{r multi-card-body-2, eval = FALSE}
card(
- height = 300, full_screen = TRUE,
- card_header("Plot with long description"),
- card_body_fill(plotly_widget),
+ height = 350,
+ full_screen = TRUE,
+ card_header(
+ "Filling plot, short description"
+ ),
+ plotly_widget,
card_body(
- height = "30%",
- lorem_ipsum_dolor_sit_amet
+ fill = FALSE,
+ card_title("A subtitle"),
+ p(class = "text-muted", "And a caption")
)
)
```
:::
+
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="multi-card-body-2", echo=FALSE}
+```
+:::
:::
-## Spacing & alignment
+## Multiple columns
+
+As you'll learn in [column-based layouts](column-layout.html), `layout_column_wrap()` is great for multi-column layouts that are responsive and accommodate for [filling output](#filling-outputs). Here we have an equal-width 2-column layout using `width = 1/2`, but it's also possible to have [varying column widths](column-layout.html#varying-widths).
::: row
::: col-md-6
-Both `card_body()` and `card_body_fill()` include padding between their contents and the `card()` container by default. In either case, you can override those defaults with Bootstrap's [spacing utility classes](https://getbootstrap.com/docs/5.2/utilities/spacing/), like `"p-0"` to remove the padding altogether. This is especially useful if
+```{r multi-cols, eval = FALSE}
+card(
+ height = 350,
+ full_screen = TRUE,
+ card_header("A multi-column filling layout"),
+ card_body(
+ min_height = 200,
+ layout_column_wrap(
+ width = 1/2,
+ plotOutput("p1"),
+ plotOutput("p2")
+ )
+ ),
+ lorem::ipsum(paragraphs = 3, sentences = 5)
+)
+```
+:::
-1. The content itself already provides sufficient padding.
-2. The content's background color is different from the card.[^2]
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="multi-cols", echo=FALSE}
+```
+:::
:::
-[^2]: There are other ways to workaround this problem other than removing padding. For example, you could set the [`card-bg` theming variable](bs5-variables.html) and/or use something like the `{thematic}` package to more generally ensure the plot styles match the card's styles.
-::: col-md-6
+## Multiple cards
+
+`layout_column_wrap()` is especially nice for laying out multiple cards since each card in a particular row will have the same height (by default). Learn more in [column-based layouts](column-layout.html).
+
```{r}
-card(
- height = 250, full_screen = TRUE,
- card_header("A stretchy plot with no padding"),
- card_body_fill(
- class = "p-0",
- plotOutput("id")
- )
+layout_column_wrap(
+ width = 1/2,
+ height = 300,
+ card(full_screen = TRUE, card_header("A filling plot"), plotly_widget),
+ card(full_screen = TRUE, card_header("A filling map"), card_body(class = "p-0", leaflet_widget))
)
```
-:::
-:::
+## Multiple tabs
-::: row
-::: col-md-6
-Utility classes are really useful since they not only also help with spacing and alignment of stuff _within_ a `card_body()` (or `card_body_fill()`), but more generally enable easy customization of colors, fonts, and more.
-:::
+`navs_tab_card()` and `navs_pill_card()` make it possible to create cards with multiple tabs or pills. These functions have the same `full_screen` capabilities as normal `card()`s as well some other options like `title` (since there is no natural place for a `card_header()` to be used). Note that, each `nav()` object is similar to a `card()`. That is, if the direct children aren't already card items (e.g., `card_title()`), they get [implicitly wrapped](#implicit-card_body) in a `card_body()`.
+::: {.row .mt-3}
::: col-md-6
-```{r}
-card(
- card_title("A title"),
- p(class = "text-muted", "Paragraph 1"),
- p(class = "text-end", "Paragraph 2"),
- div(
- class = "p-5 bg-secondary text-center",
- span("Inline comment")
+```{r multiple-tabs, eval=FALSE}
+library(leaflet)
+navs_tab_card(
+ height = 450,
+ full_screen = TRUE,
+ title = "HTML Widgets",
+ nav(
+ "Plotly",
+ card_title("A plotly plot"),
+ plotly_widget
+ ),
+ nav(
+ "Leaflet",
+ card_title("A leaflet plot"),
+ leaflet_widget
+ ),
+ nav(
+ shiny::icon("circle-info"),
+ markdown("Learn more about [htmlwidgets](http://www.htmlwidgets.org/)")
)
)
```
:::
-:::
-::: row
-::: col-md-6
-In the case of `card_body_fill()`, since it's based on [CSS flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), you can add uniform spacing between children via the `gap` argument. Note there is a similar way to space between [multiple columns](#multiple-columns).
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="multiple-tabs", echo=FALSE}
+```
+:::
:::
-::: col-md-6
+
+
+## Sidebars
+
+As you'll learn more about in [sidebar layouts](sidebars.html), `layout_sidebar()` just works when placed inside in a `card()`. In this case, if you want **fill item**s (e.g., `plotly_widget`) to still fill the card like we've [seen before](#filling-outputs), you'll need to set `fillable = TRUE` in `layout_sidebar()`.
+
```{r}
card(
- card_body_fill(
- gap = "1rem", class = "p-3",
- div(class = "bg-secondary", "Thing 1"),
- div(class = "bg-secondary", "Thing 2"),
- div(class = "bg-secondary", "Thing 3")
+ height = 300,
+ full_screen = TRUE,
+ card_header("A sidebar layout inside a card"),
+ layout_sidebar(
+ fillable = TRUE,
+ sidebar(
+ actionButton("btn", "A button")
+ ),
+ plotly_widget
)
)
```
-:::
-:::
-::: row
-::: col-md-6
-Again, thanks to CSS flexbox, if the contents of a `card_body_fill()` aren't full width, you can pretty easily horizontally center them via [flex utility classes](https://getbootstrap.com/docs/5.2/utilities/flex/) (note that you could handle similar alignment issues with `card_body()` by making it a flexbox container with `card_body(class = "d-flex")`.
-:::
+## Static images
+`card_image()` makes it easy to embed static (i.e., pre-generated) images into a card. Provide a URL to `href` to make it clickable. In the case of multiple `card_image()`s, consider laying them out in [multiple cards](#multiple-cards) with `layout_column_wrap()` to produce a grid of clickable thumbnails.
+
+::: row
::: col-md-6
-```{r}
+```{r static-images, eval = FALSE}
card(
- height = 150, full_screen = TRUE,
- card_body_fill(
- class = "p-3 align-items-center",
- plotOutput("id", width = "50%")
+ height = 300,
+ full_screen = TRUE,
+ card_image(
+ file = "shiny-hex.svg",
+ href = "https://github.com/rstudio/shiny"
+ ),
+ card_body(
+ fill = FALSE,
+ card_title("Shiny for R"),
+ p(
+ class = "fw-light text-muted",
+ "Brought to you by RStudio."
+ )
)
)
```
:::
+
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="static-images", echo=FALSE}
+```
+:::
:::
-## Dynamic rendering (Shiny)
-::: row
-::: col-md-6
-Since this article is statically rendered, the examples here use statically rendered content/widgets, but the same `card()` functionality works for dynamically rendered content via Shiny (e.g., `shiny::plotOutput()`, `plotly::plotlyOutput()`, etc).
+## Flexbox
-One neat thing about dynamic rendering is that you can leverage `shiny::getCurrentOutputInfo()` to render content differently depending on the height of its container, which is particularly useful with `card(full_screen = T, ...)`. For example, you may want additional captions/labels when a plot is large, additional controls on a table, etc (see the [value boxes](value-boxes.html) article for a clever use of this).
-:::
+::: {.row .mt-3}
+
+Both `card()` and `card_body()` default to `fillable = TRUE` (that is, they are CSS [flexbox containers](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)), which works wonders for facilitating [filling outputs](#filling-outputs), but it also leads to surprising behavior with inline tags (e.g., `actionButton()`, `span()`, strings, etc). Specifically, each inline tag is placed on a new line, but in a "normal" layout flow (`fillable = FALSE`), inline tags render _inline_.
::: col-md-6
-```{r, message=FALSE, eval=FALSE}
-# UI logic
-ui <- page_fluid(
- card(
- height = 200,
- full_screen = TRUE,
- card_header("A dynamically rendered plot"),
- card_body_fill(plotOutput("plot_id"))
+```{r flexbox, eval = FALSE}
+card(
+ card_body(
+ fillable = TRUE,
+ "Here's some", tags$i("inline"), "text",
+ actionButton("btn1", "A button")
+ ),
+ card_body(
+ fillable = FALSE,
+ "Here's some", tags$i("inline"), "text",
+ actionButton("btn2", "A button")
)
)
+```
+:::
-# Server logic
-server <- function(input, output, session) {
- output$plot_id <- renderPlot({
- info <- getCurrentOutputInfo()
- if (info$height() > 600) {
- # code for "large" plot
- } else {
- # code for "small" plot
- }
- })
-}
-
-shinyApp(ui, server)
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="flexbox", echo=FALSE}
```
:::
:::
-## Static images
-::: row
-::: col-md-6
-`card_image()` makes it easy to embed static (i.e., pre-generated) images into a card. Provide a URL to `href` to make it clickable. In the case of multiple `card_image()`s, consider laying them out in [multiple cards](#multiple-cards) with `layout_column_wrap()` to produce a grid of clickable thumbnails.
-:::
+::: {.row .mt-3}
+
+That said, sometimes working in a flexbox layout is quite useful, even when working with inline tags. Here we leverage flexbox's [`gap`](https://developer.mozilla.org/en-US/docs/Web/CSS/gap) property to control the spacing between a plot, a (full-width) button, and paragraph. Note that, by using `markdown()` for the paragraph, it wraps the results in a `
` tag, which means the _contents_ of the paragraph are not longer subject to flexbox layout. If we wanted, we could do something similar to render the `actionButton()` inline by wrapping it in a `div()`.
::: col-md-6
-```{r}
+```{r flexbox2, eval=FALSE}
card(
- height = 300, full_screen = TRUE,
- card_image(
- file = "shiny-hex.svg",
- href = "https://github.com/rstudio/shiny"
- ),
- card_title("Shiny for R"),
+ height = 325, full_screen = TRUE,
+ card_header("A plot with an action links"),
card_body(
- class = "pt-0 fs-6 lead text-muted",
- "Brought to you by RStudio."
+ class = "gap-2 container",
+ plotly_widget,
+ actionButton(
+ "go_btn", "Action button",
+ class = "btn-primary rounded-0"
+ ),
+ markdown("Here's a _simple_ [hyperlink](https://www.google.com/).")
)
)
```
:::
-:::
-
-
-## Multiple tabs
-::: row
-::: col-md-6
-`navs_tab_card()` (as well as `navs_pill_card()`) makes it easy to create cards with multiple tabs (or pills). These functions have the same `full_screen` capabilities as normal `card()`s as well some other options like `title` (since there is no natural place for a `card_header()` to be used). Note that, similar to `card()`, the children of each `nav()` panel will be implicitly wrapped in a `card_body()` call, so use `card_body_fill()` where appropriate to get [responsive sizing](#responsive-sizing).
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="flexbox2", echo=FALSE}
+```
+:::
:::
+::: {.row .mt-3}
+In addition to gap, flexbox has really nice ways of handling otherwise difficult spacing and alignment issues. And, thanks to Bootstrap's [flex utility classes](https://getbootstrap.com/docs/5.3/utilities/flex/), we can easily opt-in and customize defaults.
+
::: col-md-6
-```{r}
-library(leaflet)
-navs_tab_card(
+```{r flexbox3, eval=FALSE}
+card(
height = 300, full_screen = TRUE,
- title = "HTML Widgets",
- nav(
- "Plotly",
- card_title("A plotly plot", class = "pt-1"),
- card_body_fill(plotly_widget)
- ),
- nav(
- "Leaflet",
- card_title("A leaflet plot", class = "pt-1"),
- card_body_fill(leaflet_widget)
+ card_header(
+ class = "d-flex justify-content-between",
+ "Centered plot",
+ checkboxInput("check", " Check me", TRUE)
),
- nav(
- shiny::icon("circle-info"),
- "Learn more about",
- tags$a("htmlwidgets", href = "http://www.htmlwidgets.org/")
+ card_body(
+ class = "align-items-center",
+ plotOutput("id", width = "75%")
)
)
```
:::
+
+::: {.col-md-6 .mt-auto .mb-auto}
+```{r ref.label="flexbox3", echo=FALSE}
+```
+:::
:::
-## Multiple columns
+## Shiny
::: row
::: col-md-6
-To create multiple columns within a card, it's recommended to use `layout_column_wrap()` (which can also be used to layout [multiple cards](#multiple-cards)), especially if the height of those columns should grow/shrink as needed.
+Since this article is statically rendered, the examples here use statically rendered content/widgets, but the same `card()` functionality works for dynamically rendered content via Shiny (e.g., `plotOutput()`, `plotlyOutput()`, etc).
+
+An additional benefit that comes with using shiny is the ability to use `getCurrentOutputInfo()` to render new/different content when the output container becomes large enough, which is particularly useful with `card(full_screen = T, ...)`. For example, you may want additional captions/labels when a plot is large, additional controls on a table, etc (see the [value boxes](value-boxes.html) article for a clever use of this).
:::
::: col-md-6
-```{r}
-card(
- height = 300, full_screen = TRUE,
- layout_column_wrap(
- width = 1/2, class = "p-3",
- plotOutput("p1"),
- plotOutput("p2")
- ),
- card_body(
- height = "30%", class = "pt-0",
- lorem_ipsum_dolor_sit_amet
+```{r, message=FALSE, eval=FALSE}
+# UI logic
+ui <- page_fluid(
+ card(
+ max_height = 200,
+ full_screen = TRUE,
+ card_header("A dynamically rendered plot"),
+ plotOutput("plot_id")
)
)
+
+# Server logic
+server <- function(input, output, session) {
+ output$plot_id <- renderPlot({
+ info <- getCurrentOutputInfo()
+ if (info$height() > 600) {
+ # code for "large" plot
+ } else {
+ # code for "small" plot
+ }
+ })
+}
+
+shinyApp(ui, server)
```
:::
:::
-## Multiple cards
-
-See the article on layout, specifically the [section on `layout_column_wrap()`](layouts.html#layout_column_wrap) to learn about useful ways to layout multiple cards.
-
## Appendix
The following CSS is used to give `plotOutput()` a background color; it's necessary here because this documentation page is not actually hooked up to a Shiny app, so we can't show a real plot.
diff --git a/vignettes/layouts.Rmd b/vignettes/column-layout.Rmd
similarity index 69%
rename from vignettes/layouts.Rmd
rename to vignettes/column-layout.Rmd
index 9705e9094..93c6c1557 100644
--- a/vignettes/layouts.Rmd
+++ b/vignettes/column-layout.Rmd
@@ -1,23 +1,9 @@
---
-title: "UI Layouts"
+title: "Column-based layout"
---
-This article gives an overview of user interface (UI) layout options available in bslib. These options aim to fill a void left by other [layout options available in Shiny](https://shiny.rstudio.com/articles/layout-guide.html), (e.g., `fluidRow()`, `column()`, `sidebarLayout()`, etc). As of right now, these options include:
-
-1. A [modern take on column-based layout](#responsive-column-first-layout), which responsively wraps a 1d sequence of UI elements into a 2d grid.
-
-2. A new, more flexible, consistent, and fully-featured way to create segmented layouts (i.e., a new approach to `tabPanel()`, `tabsetPanel()`, `navlistPanel()`, etc).
-
- * One obvious new feature is [multiple tabs/pills within a card](cards.html#multiple-tabs) (i.e., `navs_tab_card()`).
- * Other, less obvious, features this new `nav()` API provides a way to right-align tabs/pills (`nav_spacer()`), embed external links and other UI elements (`nav_item()`), include multiple navbars (`navs_bar()`), and more (see the examples section of `navs_tab()`).
-
-3. Various `page_*()` containers (e.g., `page_fluid()`, `page_navbar()`, etc).
- * As of right now, these are just a drop-in replacement for their respective Shiny version (e.g., `page_fluid()` instead of `fluidPage()`) that only changes the default of the `theme` argument to `bs_theme()`.
-
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
-
-lorem_ipsum_dolor_sit_amet <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Id nibh tortor id aliquet lectus proin nibh nisl. Adipiscing at in tellus integer feugiat. Arcu bibendum at varius vel pharetra vel turpis nunc eget. Cursus sit amet dictum sit amet justo. Sit amet consectetur adipiscing elit. Vestibulum mattis ullamcorper velit sed ullamcorper. Enim facilisis gravida neque convallis a. Elit duis tristique sollicitudin nibh sit amet. Magna eget est lorem ipsum. Gravida dictum fusce ut placerat orci nulla pellentesque dignissim. Mauris in aliquam sem fringilla ut morbi. Id semper risus in hendrerit gravida rutrum quisque non tellus. At erat pellentesque adipiscing commodo elit at imperdiet dui. Fames ac turpis egestas maecenas pharetra convallis posuere morbi. Duis convallis convallis tellus id interdum velit laoreet id. Aliquet lectus proin nibh nisl. Nunc vel risus commodo viverra maecenas accumsan lacus vel facilisis. Bibendum enim facilisis gravida neque convallis a."
```
```{css, echo = FALSE}
@@ -29,9 +15,7 @@ lorem_ipsum_dolor_sit_amet <- "Lorem ipsum dolor sit amet, consectetur adipiscin
```{r ref.label="anim_helpers",echo=FALSE}
```
-## Responsive column-first layout
-
-This section outlines various layouts made possible by `layout_column_wrap()`. To illustrate, we'll use three `card()` instances with varying content, but keep in mind that `layout_column_wrap()` is designed to work other UI elements as well, such as [value boxes](value-boxes.html) or even for [multiple columns within a card](card.html#multiple-columns).
+This article outlines various layouts made possible by `layout_column_wrap()`. To illustrate, we'll use three `card()` instances with varying content, but keep in mind that `layout_column_wrap()` is designed to work other UI elements as well, such as [value boxes](value-boxes.html) or even for [multiple columns within a card](card.html#multiple-columns).
**Note:** The examples in this section are not intended to be viewed on mobile devices. At small window widths, all of the layouts here collapse into a more mobile-friendly approach of "show each card at maximum width".
@@ -40,7 +24,10 @@ library(bslib)
card1 <- card(
card_header("Scrolling content"),
- card_body(lorem_ipsum_dolor_sit_amet, fill = TRUE)
+ lapply(
+ lorem::ipsum(paragraphs = 3, sentences = c(5, 5, 5)),
+ tags$p
+ )
)
card2 <- card(
card_header("Nothing much here"),
@@ -49,7 +36,7 @@ card2 <- card(
card3 <- card(
full_screen = TRUE,
card_header("Filling content"),
- card_body_fill(
+ card_body(
class = "p-0",
shiny::plotOutput("p")
)
@@ -121,14 +108,16 @@ layout_column_wrap(
anim_height(300, 450)
```
-#### By column
+#### By cell
-By default, each the height on each card grows to fill the available vertical space in a particular row. To opt out of that behavior, set `fill = FALSE`.
+By default, each the height on each card grows to fill the available vertical space in a particular row. This can be prevented
```{r}
layout_column_wrap(
- width = "200px", fill = FALSE,
- card1, card2, card3
+ width = "200px",
+ #heights_equal = "row",
+ fillable = FALSE,
+ card1, card3, card2
) |>
anim_height(300, 450)
```
@@ -166,7 +155,7 @@ layout_column_wrap(
### Other grid-based layouts
-`layout_column_wrap()` provides a simplified interface to [CSS grid](https://css-tricks.com/snippets/css/complete-guide-grid/) that won't accomodate everything it can do. In this case, we recommend using `{gridlayout}` and/or the [Shiny UI editor](https://rstudio.github.io/shinyuieditor/) to produce the layout.
+`layout_column_wrap()` provides a simplified interface to [CSS grid](https://css-tricks.com/snippets/css/complete-guide-grid/) that won't accommodate everything it can do. In this case, we recommend using `{gridlayout}` and/or the [Shiny UI editor](https://rstudio.github.io/shinyuieditor/) to produce the layout.
## Appendix
diff --git a/vignettes/filling.Rmd b/vignettes/filling.Rmd
new file mode 100644
index 000000000..c1bc0e43b
--- /dev/null
+++ b/vignettes/filling.Rmd
@@ -0,0 +1,676 @@
+---
+title: "Filling layouts"
+resource_files:
+ - infobox.svg
+ - examples/filling
+---
+
+```{r setup, include = FALSE}
+library(knitr)
+library(htmltools)
+library(bslib)
+library(shiny)
+library(plotly)
+
+# TODO: put this stuff in a common.R script?
+render_as_iframe <- function(x, options, ...) {
+ lbl <- opts_current$get("label")
+ doc_name <- sub("[.]Rmd", "", current_input())
+ lbl_dir <- file.path("examples", doc_name, lbl)
+ if (!dir.exists(lbl_dir)) {
+ dir.create(lbl_dir, recursive = TRUE)
+ }
+ file <- file.path(lbl_dir, paste0(lbl, ".html"))
+ x <- tagList(x, tags$head(tags$style(".modebar-container { display: none; }")))
+ tryCatch(
+ save_html(x, file),
+ error = function(e) {
+ stop("Don't know how to render ", class(x)[[1]], " as an