From bf0090dd6dcbae2fadef91d5f18b81b10c17fbf4 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Sat, 13 Jun 2026 22:29:42 -0700 Subject: [PATCH 1/4] Convert list group and card group to container queries Replace viewport media queries with container queries for the responsive .*:list-group-horizontal variants and the .card-group row layout, using the existing container-breakpoint-up mixins. Both now respond to the width of a parent query container (e.g., .contains-inline) rather than the viewport. Update the docs to reflect the new behavior, flip css_media to container, and list both components under the container queries guide. --- scss/_card.scss | 5 ++++- scss/_list-group.scss | 11 +++++----- site/src/content/docs/components/card.mdx | 14 +++++++++---- .../content/docs/components/list-group.mdx | 20 +++++++++++++++---- site/src/content/docs/layout/breakpoints.mdx | 4 ++++ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/scss/_card.scss b/scss/_card.scss index 62c1e7d24969..f099ba85f81d 100644 --- a/scss/_card.scss +++ b/scss/_card.scss @@ -235,6 +235,9 @@ $card-tokens: defaults( // Card groups // + // Card groups lay out their cards in a row using a container query, so wrap the + // group in a query container (e.g., the `.contains-inline` utility) for the row + // layout to take effect. Without a query container the cards remain stacked. .card-group { // The child selector allows nested `.card` within `.card-group` // to display properly. @@ -242,7 +245,7 @@ $card-tokens: defaults( margin-bottom: var(--card-group-margin); } - @include media-breakpoint-up(sm) { + @include container-breakpoint-up(sm) { display: flex; flex-flow: row wrap; // The child selector allows nested `.card` within `.card-group` diff --git a/scss/_list-group.scss b/scss/_list-group.scss index 52b0e4b424ce..6ab8b1c542bb 100644 --- a/scss/_list-group.scss +++ b/scss/_list-group.scss @@ -1,4 +1,3 @@ -@use "sass:map"; @use "config" as *; @use "functions" as *; @use "mixins/border-radius" as *; @@ -136,12 +135,12 @@ $list-group-tokens: defaults( // Horizontal // // Change the layout of list group items from vertical (default) to horizontal. + // The responsive variants use container queries, so wrap the list group in a + // query container (e.g., the `.contains-inline` utility) for them to take effect. - @each $breakpoint in map.keys($breakpoints) { - @include media-breakpoint-up($breakpoint) { - $prefix: breakpoint-prefix($breakpoint, $breakpoints); - - .#{$prefix}list-group-horizontal { + @include loop-breakpoints-up() using ($breakpoint, $prefix) { + .#{$prefix}list-group-horizontal { + @include container-breakpoint-up($breakpoint) { flex-direction: row; > .list-group-item { diff --git a/site/src/content/docs/components/card.mdx b/site/src/content/docs/components/card.mdx index 43d64d28fab2..b0cfb7c0e424 100644 --- a/site/src/content/docs/components/card.mdx +++ b/site/src/content/docs/components/card.mdx @@ -3,7 +3,7 @@ title: Cards description: Bootstrap’s cards provide a flexible and extensible content container with multiple variants and options. toc: true css_layer: components -css_media: viewport +css_media: container --- import { getData } from '@libs/data' @@ -425,13 +425,16 @@ Add `.card-translucent` to blur and saturate the background of a card. Header an ## Card layout -In addition to styling the content within cards, Bootstrap includes a few options for laying out series of cards. For the time being, **these layout options are not yet responsive**. +In addition to styling the content within cards, Bootstrap includes a few options for laying out series of cards. ### Card groups Use card groups to render cards as a single, attached element with equal width and height columns. Card groups start off stacked and use `display: flex;` to become attached with uniform dimensions starting at the `sm` breakpoint. - +This layout uses [container queries]([[docsref:/layout/breakpoints#container-queries]]), so wrap the card group in a query container—add the `.contains-inline` utility to a parent element—for the row layout to take effect. Without a query container, the cards remain stacked. + + +
@@ -456,11 +459,13 @@ Use card groups to render cards as a single, attached element with equal width a

Last updated 3 mins ago

+
`} /> When using card groups with footers, their content will automatically line up. - + +
@@ -491,6 +496,7 @@ When using card groups with footers, their content will automatically line up. Last updated 3 mins ago
+
`} /> ### Grid cards diff --git a/site/src/content/docs/components/list-group.mdx b/site/src/content/docs/components/list-group.mdx index bbc26475730c..1a386184a1cd 100644 --- a/site/src/content/docs/components/list-group.mdx +++ b/site/src/content/docs/components/list-group.mdx @@ -3,7 +3,7 @@ title: List group description: List groups are a flexible and powerful component for displaying a series of content. Modify and extend them to support just about any content within. toc: true css_layer: components -css_media: viewport +css_media: container --- import { getData } from '@libs/data' @@ -114,17 +114,29 @@ These work great with custom content as well. ## Horizontal -Add `.list-group-horizontal` to change the layout of list group items from vertical to horizontal across all breakpoints. Alternatively, choose a responsive variant `.{sm|md|lg|xl|2xl}:list-group-horizontal` to make a list group horizontal starting at that breakpoint’s `min-width`. Currently **horizontal list groups cannot be combined with flush list groups.** +Add `.list-group-horizontal` to change the layout of list group items from vertical to horizontal across all container sizes. Alternatively, choose a responsive variant `.{sm|md|lg|xl|2xl}:list-group-horizontal` to make a list group horizontal starting at that breakpoint’s width. + +The responsive variants use [container queries]([[docsref:/layout/breakpoints#container-queries]]), so wrap the list group in a query container—add the `.contains-inline` utility to a parent element—for them to take effect. Currently **horizontal list groups cannot be combined with flush list groups.** **ProTip:** Want equal-width list group items when horizontal? Add `.flex-fill` to each list group item. `
    + code={getData('breakpoints').map((breakpoint) => `
    +
      +
    • An item
    • +
    • A second item
    • +
    • A third item
    • +
    +
    `)} /> + +Drag the handle to resize the container below and watch the list group switch between vertical and horizontal layouts as the container—not the viewport—crosses the `md` breakpoint. + +
  • An item
  • A second item
  • A third item
  • -
`)} /> + `} /> ## Variants diff --git a/site/src/content/docs/layout/breakpoints.mdx b/site/src/content/docs/layout/breakpoints.mdx index b837af51400e..f06f9ad0fed7 100644 --- a/site/src/content/docs/layout/breakpoints.mdx +++ b/site/src/content/docs/layout/breakpoints.mdx @@ -183,6 +183,10 @@ The following components use container queries: - **[Stepper]([[docsref:/components/stepper]])** — The `.stepper-overflow` wrapper uses `container-type: inline-size` to establish a containment context for the horizontally scrolling stepper pattern. +- **[List group]([[docsref:/components/list-group]])** — The `.*:list-group-horizontal` classes use `@container` queries so the list group switches between vertical and horizontal layouts based on the width of its query container rather than the viewport. + +- **[Card]([[docsref:/components/card]])** — The `.card-group` layout uses an `@container` query to attach cards into equal-width columns based on the width of its query container rather than the viewport. + Here’s how the navbar implements container queries: ```scss From 8e8b290e7ea9ffb212dd158588cedc00856a330e Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Sat, 13 Jun 2026 22:44:22 -0700 Subject: [PATCH 2/4] Document container query migration for card group and list group --- site/src/content/docs/guides/migration.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/src/content/docs/guides/migration.mdx b/site/src/content/docs/guides/migration.mdx index 6b48ed0abafe..54aa83480fa5 100644 --- a/site/src/content/docs/guides/migration.mdx +++ b/site/src/content/docs/guides/migration.mdx @@ -209,6 +209,8 @@ Bootstrap 6 is a major release with many breaking changes to modernize our codeb - Theme coloring via `.theme-*` classes on the `.accordion` wrapper. - **Rebuilt close button markup.** `.btn-close` now renders its icon via a CSS `mask-image` (`--btn-close-icon`) tinted with `background-color: currentcolor`, so the button is self-contained—no child `` is required. The filter-based dark mode approach (`$btn-close-white-filter`) has been replaced by `currentcolor` inheritance, and the `.btn-close-white` class has been removed—on dark backgrounds (e.g., `.text-bg-dark`) the icon now inherits the contrast color automatically. - **Restructured cards.** Borders now live on `.card-body` and `.card-list` segments rather than a single outer `.card` border. Added `--card-box-shadow` and `--card-body-gap` tokens. New variant classes: `.card-translucent` (frosted glass effect) and `.card-subtle` (themed with subtle backgrounds). Horizontal cards use a new `.card-row` class. +- **Card groups now use container queries.** `.card-group` switches to its attached, equal-width row layout with a `@container` query instead of a viewport `@media` query, so it responds to the width of a parent query container rather than the viewport. Wrap the card group in a query container—e.g. add the `.contains-inline` utility to a parent element—or the cards stay stacked. +- **List group horizontal variants now use container queries.** The `.*:list-group-horizontal` classes switch between vertical and horizontal layouts with `@container` queries instead of viewport `@media` queries, responding to a parent query container rather than the viewport. Wrap the list group in a query container (e.g. `.contains-inline`) for the responsive variants to take effect. - **Reworked badge variants.** Badge color variants now use `.badge-subtle` and `.badge-outline` combined with `.theme-*` classes (e.g., `.badge-subtle .theme-primary`), replacing the v5 `.bg-primary` utility pattern on badges. - **Updated breadcrumb markup.** Breadcrumbs now use `.breadcrumb-link` as an interactive element with padding, min-height, and hover background, and explicit `.breadcrumb-divider` elements as separators between items. An empty `.breadcrumb-divider` renders a default chevron via a CSS `mask-image` (`--breadcrumb-divider-icon`) tinted with `background-color: currentcolor`; add your own SVG, text, or markup inside it to override. This replaces the v5 `--bs-breadcrumb-divider` content string on the `.breadcrumb-item::before` pseudo-element. - **Navbar toggler icon now uses a CSS mask.** `.navbar-toggler-icon` renders via `mask-image` (`--navbar-toggler-icon`) tinted with `background-color: currentcolor` instead of an embedded `background-image` SVG. The markup stays an empty ``, but the icon now inherits the current text color (including dark mode), so the separate light/dark toggler SVGs are no longer needed. From ccb8339ab885e6ec6f4541f00de42f349373d5e5 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Sun, 14 Jun 2026 14:41:08 -0700 Subject: [PATCH 3/4] Fix doubled card-group borders by overlapping adjacent cards The v6 border model moved borders off the outer .card onto the inner segments (.card-header, .card-body, .card-list, .card-footer) and the card images use outlines. The card-group seam code still removed border-inline-start from .card, which no longer has a border, so adjacent cards rendered doubled borders at every seam (body, header, and footer). Pull each subsequent card back by one border width with a negative inline margin so its leading edges overlap the previous card's trailing edge, collapsing every seam into a single line. --- scss/_card.scss | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scss/_card.scss b/scss/_card.scss index f099ba85f81d..96def9734d3b 100644 --- a/scss/_card.scss +++ b/scss/_card.scss @@ -254,9 +254,14 @@ $card-tokens: defaults( flex: 1 0 0; margin-bottom: 0; + // Borders now live on the inner segments (header, body, list, footer) + // and the card images use outlines, so adjacent cards would otherwise + // render a doubled-up border at each seam. Pull subsequent cards back by + // one border width so their leading edges overlap the previous card's + // trailing edge, collapsing the seam into a single line. Gap can't be + // negative, so this relies on a negative margin. + .card { - margin-inline-start: 0; - border-inline-start: 0; + margin-inline-start: calc(-1 * var(--card-border-width)); } // Handle rounded corners From 92aca1ec2a1ee5d2ba5bc4f7c05527aee1ec745e Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Mon, 15 Jun 2026 12:29:23 -0700 Subject: [PATCH 4/4] Fix doubled border between card body and footer A middle .card-body/.card-list draws a bottom border to divide itself from the next segment, but .card-footer draws a full border including its top edge, so the shared seam rendered as a doubled border whenever a footer followed a body that wasn't the first child (e.g. image + body + footer, or header + body + footer). Drop the body/list bottom border when a footer immediately follows so the footer owns that divider. --- scss/_card.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scss/_card.scss b/scss/_card.scss index 96def9734d3b..4a89d125be55 100644 --- a/scss/_card.scss +++ b/scss/_card.scss @@ -91,6 +91,13 @@ $card-tokens: defaults( &:not(:first-child, :last-child) { border-block-end-width: var(--card-border-width); } + + // The footer draws a full border (including its top edge), so a body/list + // segment that precedes it must not also draw a bottom border or the seam + // doubles up. + &:has(+ .card-footer) { + border-block-end-width: 0; + } } .card-title,