twbs/bootstrap

bootstrap-v5-v6-migration

Migrate projects from Bootstrap 5 to Bootstrap 6.

查看源码
仓库原始内容

按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。

Bootstrap v5 to v6 Migration

Workflow

Work through each step in order. After each step, search the codebase for remaining v5 patterns before moving on.

  • [ ] Step 1: Update dependencies and build setup
  • [ ] Step 2: Rename CSS classes and data attributes
  • [ ] Step 3: Restructure component HTML
  • [ ] Step 4: Update JavaScript
  • [ ] Step 5: Update Sass
  • [ ] Step 6: Verify

Step 1: Dependencies & Build

  1. Update package.json: "bootstrap": "6.0.0-alpha.1"
  2. Replace @popperjs/core with @floating-ui/dom
  3. If using Datepicker, add peer dep vanilla-calendar-pro
  4. Sass: replace all @import with @use (Node Sass is no longer supported)

bootstrap.bundle.js includes Floating UI and Vanilla Calendar Pro. Standalone bootstrap.js leaves both peer dependencies external. Direct browser loading of the standalone build needs an import map.

scss
// v5
@import "bootstrap/scss/bootstrap";

// v6
@use "bootstrap/scss/bootstrap";

// v6 with overrides — customize CSS tokens through the token maps
@use "bootstrap/scss/bootstrap" with (
  $root-tokens: (
    --spacer: 1rem,
  )
);

Customize by overriding the CSS token maps — $root-tokens for global tokens and each component's $*-tokens map — rather than legacy Sass scalars. See Customize › Sass. Token names are written unprefixed in Sass (e.g. --spacer, --border-radius); Bootstrap's dist/CDN CSS runs PostCSS to add the --bs- prefix (--bs-spacer), so when you compile the source yourself the properties stay unprefixed.


Step 2: CSS Class & Attribute Renames

Responsive & state prefix syntax

v6 moves breakpoints and pseudo-states from infix/suffix to prefix with colon. Also renames xxl to 2xl.

Pattern: .{class}-{bp}-{value} becomes .{bp}:{class}-{value} and .{class}-{bp} becomes .{bp}:{class}

v5v6
.d-md-none, .p-lg-3.md:d-none, .lg:p-3
.col-md-6.md:col-6
.row-cols-md-3.md:row-cols-3
.offset-md-2.md:offset-2
.g-md-3, .gx-md-3.md:g-3, .md:gx-3
.g-col-md-4.md:g-col-4
.container-sm.sm:container
.navbar-expand-md.md:navbar-expand
.offcanvas-md.md:drawer
.table-responsive-md.md:table-responsive
.list-group-horizontal-md.md:list-group-horizontal
.sticky-md-top.md:sticky-top
.vstack-md.md:vstack
.dialog-fullscreen-sm-down.sm-down:dialog-fullscreen
.d-print-none.print:d-none
.opacity-50-hover.hover:opacity-50

The prefix does not identify the query type. Utilities, grid columns, containers, drawers, and responsive tables use viewport queries. Stacks, CSS Grid columns, navbar expansion, horizontal list groups, card groups, and stacked tables use container queries. Add the query container that each component’s documentation requires.

Component renames

Three components have been fully renamed. Find-and-replace these prefixes across classes, data attributes, events, JS imports, and CSS variables.

Modal -> Dialog

Scopev5v6
Classes.modal, .modal-header/body/footer/title.dialog, .dialog-header/body/footer/title
Sizes.modal-sm/lg/xl/fullscreen.dialog-sm/lg/xl/fullscreen
Data attrsdata-bs-toggle="modal", data-bs-dismiss="modal"data-bs-toggle="dialog", data-bs-dismiss="dialog"
JS exportModalDialog
Events*.bs.modal*.bs.dialog
CSS vars--modal-*--dialog-*
Body class.modal-open on <body>.dialog-open on <html>

Remove .modal-dialog and .modal-content wrappers entirely — see Step 3.

Offcanvas -> Drawer

Scopev5v6
Classes.offcanvas, .offcanvas-start/end/top/bottom/header/body/title.drawer, .drawer-start/end/top/bottom/header/body/title
Data attrsdata-bs-toggle="offcanvas", data-bs-dismiss="offcanvas"data-bs-toggle="drawer", data-bs-dismiss="drawer"
JS exportOffcanvasDrawer
Events*.bs.offcanvas*.bs.drawer
CSS vars--offcanvas-*--drawer-*
Sass$zindex-offcanvas$zindex-drawer

Dropdown -> Menu

Scopev5v6
Classes.dropdown-menu, .dropdown-item, .dropdown-divider, .dropdown-header.menu, .menu-item, .menu-divider, .menu-header
Data attrsdata-bs-toggle="dropdown"data-bs-toggle="menu"
JS exportDropdownMenu
Events*.bs.dropdown*.bs.menu
Sass$zindex-dropdown$zindex-menu

Also remove: .dropdown-toggle (no longer needed), .dropdown wrapper, .dropdown-toggle-split. See Step 3 for new markup.

Button & badge variants -> theme tokens

Per-color classes are replaced by variant + .theme-* composition. Built-in theme keys are primary, accent, success, danger, warning, info, inverse, and secondary. Apply both classes to the same element.

v5v6
.btn-primaryclass="btn-solid theme-primary"
.btn-outline-primaryclass="btn-outline theme-primary"
.alert-primaryclass="alert theme-primary"
.badge.bg-primaryclass="badge theme-primary"

New button variants: .btn-solid, .btn-outline, .btn-subtle, .btn-text, .btn-styled, .btn-link.

Use .theme-reset on a nested subtree to drop inherited --theme-* tokens and return to component defaults.

There are no .theme-light or .theme-dark classes. Review v5 light and dark variants manually. Use neutral surface utilities, color modes, or .theme-inverse as appropriate.

Placeholder animations

Use .placeholder-wave for the standard loading animation. Replace .placeholder-glow with .placeholder-pulse when you want the old opacity animation. .placeholder-glow remains as a compatibility alias.

Utility class renames

v5v6
.text-primary, .text-danger, etc..fg-primary, .fg-danger, etc.
.text-muted.fg-secondary
.mh-*.max-h-*
.mw-*.max-w-*
.form-select.form-control (on <select>)
.clearfix.d-flow-root
.has-validationRemove (no longer needed)
.lh-base.lh-md
.text-bg-primaryclass="bg-primary fg-contrast-primary"
.link-offset-*, .link-underline-*.underline-offset-*, .underline-*

Remove .display-1 through .display-6 and .lead. Compose their styles with .fs-* and .fw-* utilities. Review .bg-light, .bg-dark, and .bg-body-*; use the v6 neutral surfaces and color modes described in the migration guide.

Font size classes

v6 replaces the numeric scale with t-shirt sizes (ascending). The full v6 scale is xs sm md lg xl 2xl 3xl 4xl 5xl 6xl. The rem values below are the v5 sizes, shown only to help you match each class.

v5 (size)v6
.fs-1 (2.5rem).fs-4xl
.fs-2 (2rem).fs-3xl
.fs-3 (1.75rem).fs-2xl
.fs-4 (1.5rem).fs-xl
.fs-5 (1.25rem).fs-lg
.fs-6 (1rem).fs-md

Note: in v6, lg and larger are fluid `clamp()` values that scale with the viewport between a min and a max (e.g. 4xl is clamp(2.25rem, 1.75rem + 2.5vw, 3rem)); xs/sm/md stay fixed. So sizes won't match v5 exactly — the mapping preserves the relative scale, not the precise rem.

Spacer scale

Keys 2-5 have changed values. To preserve v5 spacing: .p-2 (0.5rem) -> .p-3, .p-3 (1rem) -> .p-5, .p-4 (1.5rem) -> .p-7, .p-5 (3rem) -> .p-12.

Keyv5v6
20.5rem0.375rem
31rem0.5rem
41.5rem0.75rem
53rem1rem
6-12—1.25rem through 3rem, in 0.25rem steps

Form validation

v5v6
.needs-validation on <form>data-bs-validate on <form>
.was-validated via JSRemove — :user-invalid handles it
<div class="valid-tooltip"><div class="tooltip valid-tooltip">
<div class="invalid-tooltip"><div class="tooltip invalid-tooltip">

Step 3: Structural HTML Changes

These components have fundamentally new markup, not just class renames.

Dialog (was Modal)

Remove the .modal-dialog and .modal-content wrappers. Use a single <dialog> element. The backdrop is now native ::backdrop.

html
<!-- v5 -->
<div class="modal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">Content</div>
      <div class="modal-footer">
        <button class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

<!-- v6 -->
<dialog class="dialog" id="exampleDialog">
  <div class="dialog-header">
    <h5 class="dialog-title">Title</h5>
    <button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close"></button>
  </div>
  <div class="dialog-body">Content</div>
  <div class="dialog-footer">
    <button class="btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
  </div>
</dialog>

Drawer (was Offcanvas)

Use a native <dialog> element. A renamed <div class="drawer"> does not work.

html
<!-- v5 -->
<div class="offcanvas offcanvas-start" id="menu">...</div>

<!-- v6 -->
<dialog class="drawer drawer-start" id="menu">...</dialog>

For responsive navbars, change data-bs-toggle="collapse" to data-bs-toggle="drawer". Replace .collapse.navbar-collapse with a <dialog class="drawer"> that contains .drawer-header and .drawer-body. Rename .navbar-expand-md to .md:navbar-expand, and remove .navbar-light or .navbar-dark.

Accordion

Replace Collapse JS with native <details>/<summary>. The name attribute creates exclusive groups (replaces data-bs-parent). Add .accordion-icon SVG inside <summary>. Remove .accordion-button and .accordion-collapse. New modifiers: .accordion-sm for compact padding and type, .accordion-gap to space items as separate rounded cards.

html
<!-- v5 -->
<div class="accordion" id="myAccordion">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#collapseOne">
        Item 1
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#myAccordion">
      <div class="accordion-body">Content</div>
    </div>
  </div>
</div>

<!-- v6 -->
<div class="accordion">
  <details class="accordion-item" name="myAccordion" open>
    <summary class="accordion-header">
      Item 1
      <svg class="accordion-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="m2 5 6 6 6-6"/></svg>
    </summary>
    <div class="accordion-body">Content</div>
  </details>
</div>

Cards

Review card markup and any custom card CSS. v6 changes card borders, layout, and several helper classes.

  • .card owns the background, outer border, radius, shadow, and height. Headers and footers draw only their divider border.
  • .card-body is optional. It is now a flex column that removes direct-child block margins and uses --card-body-gap for spacing. Add .flex-row for a horizontal body.
  • Keep .list-group-flush on list groups inside cards. Do not add .card-list; that class is not available.
  • .card-title and .card-text no longer add styles. Keep them only as project hooks. .card-subtitle still reduces the gap above the subtitle.
  • .card-link is removed. Use normal links and flex or gap utilities when you need a link row.
  • Use .card-row for horizontal cards. Use .card-subtle or .card-translucent for the new visual variants.
  • Card groups now use a container query. Add .contains-inline to a parent or the cards remain stacked.

Menu (was Dropdown)

Remove .dropdown wrapper and .dropdown-toggle. Flatten <ul><li><a> to <div><a>. Toggle and .menu are siblings.

html
<!-- v5 -->
<div class="dropdown">
  <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Menu</button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a class="dropdown-item" href="#">Other</a></li>
  </ul>
</div>

<!-- v6 -->
<button class="btn-solid theme-secondary" data-bs-toggle="menu">Menu</button>
<div class="menu">
  <a class="menu-item" href="#">Action</a>
  <hr class="menu-divider">
  <a class="menu-item" href="#">Other</a>
</div>

Close button

The markup does not change — .btn-close stays an empty element. Do not add a child SVG (that double-renders the icon). What changed is internal: v6 draws the icon with a CSS mask (--btn-close-icon) over background-color: currentcolor, so the button now inherits the current text color instead of a fixed image.

html
<!-- v5 and v6 — identical markup -->
<button type="button" class="btn-close" aria-label="Close"></button>

Because the icon is currentcolor, the v5 .btn-close-white variant is removed — to get a light close button, set the text color (e.g. place it in a dark .theme-* context or add a .fg-* / color utility) instead.

Checkbox

Apply .check directly on the <input>. No wrapper and no inline SVG — the mark is a CSS mask on ::before. Radios (.radio) follow the same pattern. Switches keep a .switch wrapper around the input.

html
<!-- v5 -->
<div class="form-check">
  <input class="form-check-input" type="checkbox" id="check1">
  <label class="form-check-label" for="check1">Check me</label>
</div>

<!-- v6 -->
<div class="form-field">
  <input type="checkbox" id="check1" class="check">
  <label for="check1">Check me</label>
</div>

Radio and switch equivalents:

html
<!-- v6 radio -->
<div class="form-field">
  <input type="radio" id="radio1" class="radio">
  <label for="radio1">Pick me</label>
</div>

<!-- v6 switch -->
<div class="form-field">
  <div class="switch">
    <input type="checkbox" id="switch1" role="switch" switch>
  </div>
  <label for="switch1">Toggle me</label>
</div>

Toggle buttons

Input is now nested inside the label. .btn-check goes on the label. No id/for needed.

html
<!-- v5 -->
<input type="checkbox" class="btn-check" id="toggle1" autocomplete="off">
<label class="btn btn-outline-primary" for="toggle1">Toggle</label>

<!-- v6 -->
<label class="btn-check btn-solid theme-primary">
  <input type="checkbox" autocomplete="off">
  Toggle
</label>

Range

.form-range is now a wrapper and a JavaScript hook. Move the class from the input to a wrapper and add .form-range-input to the input.

html
<!-- v5 -->
<input type="range" class="form-range">

<!-- v6 -->
<div class="form-range">
  <input type="range" class="form-range-input">
</div>

Breadcrumbs

Add .breadcrumb-link on <a> elements. Add empty .breadcrumb-divider separators between items (replaces ::before pseudo-elements). An empty divider renders a default chevron via a CSS mask. The default bottom margin is gone (v5 used $spacer).

html
<!-- v5 -->
<ol class="breadcrumb">
  <li class="breadcrumb-item"><a href="#">Home</a></li>
  <li class="breadcrumb-item active">Library</li>
</ol>

<!-- v6 -->
<ol class="breadcrumb">
  <li class="breadcrumb-item"><a class="breadcrumb-link" href="#">Home</a></li>
  <li class="breadcrumb-divider"></li>
  <li class="breadcrumb-item"><a class="breadcrumb-link active" href="#">Library</a></li>
</ol>

Step 4: JavaScript

ESM-only

All dist files are now ES modules. No more UMD bundles or window.bootstrap global.

html
<!-- v5 -->
<script src="bootstrap.bundle.min.js"></script>

<!-- v6 -->
<script type="module" src="bootstrap.bundle.min.js"></script>

Replace global namespace access with imports:

js
// v5 — global namespace
const tooltip = bootstrap.Tooltip.getOrCreateInstance(el)
js
// v6 — explicit import
import { Tooltip } from './bootstrap.bundle.min.js'

const tooltip = Tooltip.getOrCreateInstance(el)

Data API initialization still runs automatically after you add type="module". Apply the component and data attribute renames in this skill. Bundler imports (import { X } from 'bootstrap') work as before.

The bundled build includes Floating UI and Vanilla Calendar Pro. The standalone build requires installed peers or a browser import map.

Renamed JS exports

v5v6
ModalDialog
OffcanvasDrawer
DropdownMenu

Popper -> Floating UI

Replace @popperjs/core with @floating-ui/dom. Rename the popperConfig option to floatingConfig on Tooltip, Popover, and Menu.

Lifecycle methods return a promise

show(), hide(), toggle(), and close() now return a promise that resolves when the transition ends. You can await them instead of listening for shown.bs.* / hidden.bs.*. The events still fire.

Hover and focus tooltips stay open while the pointer or focus is on the tip itself (WCAG 1.4.13). Press Escape or leave both the trigger and the tip to hide it.

Popup datepickers close on outside interaction, on <kbd>Escape</kbd>, or when focus leaves the input and calendar.

TypeScript declarations

Bootstrap’s source is now TypeScript. The package includes type declarations, so remove @types/bootstrap. Deep .js imports resolve to compiled js/dist files.

Removed

  • jQuery support
  • bootstrap.esm.js / bootstrap.esm.min.js — use bootstrap.js
  • js/index.umd.js

Validation JS

js
// v5
document.querySelectorAll('.needs-validation')
form.classList.add('was-validated')

// v6
document.querySelectorAll('form[data-bs-validate]')
// Remove the was-validated line entirely

Step 5: Sass

Renamed files

v5v6
_variables.scss_config.scss
_variables-dark.scssRemoved (merged into _theme.scss)
_maps.scssRemoved
_placeholders.scss_placeholder.scss
_spinners.scss_spinner.scss
_form-check.scss_check.scss, _radio.scss, _switch.scss
mixins/_forms.scssmixins/_form-validation.scss
forms/_form-variables.scssRemoved
vendor/_rfs.scssRemoved

Renamed variables and functions

v5v6
$grid-breakpoints$breakpoints
$border-radius, $border-radius-sm/lg/xl/xxl, $border-radius-pillRemoved — see the radius scale below
$text-mutedUse secondary color
$hr-bg-color$hr-border-color
$hr-height$hr-border-width
$zindex-dropdown$zindex-menu
$zindex-offcanvas$zindex-drawer
$form-validation-states$validation-states
$btn-close-white-filterRemoved — icon uses currentcolor
add() / subtract()calc()
breakpoint-infix()breakpoint-prefix() (returns "md\:" not "-md")
$infix (in loop mixins)$prefix
$prefix (CSS var prefix)Removed — use PostCSS instead

Border radius scale

The $border-radius-* variables are gone. v6 uses a single base $radius: .5rem and a $radii map (keys 0–9, e.g. 5: $radius, 9: $radius * 2), exposed as --radius-0–--radius-9 tokens (plus --radius-pill). The .rounded-* utilities now span 0–9 and map to different values than v5, so shift class numbers up to keep the same roundness (e.g. .rounded-1 → .rounded-3, .rounded-3 → .rounded-5). Override the base or the map entries rather than the old per-size variables:

scss
// $radius lives in _config.scss, so configure that module before loading Bootstrap
@use "bootstrap/scss/config" with (
  $radius: .375rem // scales the whole map
);
@use "bootstrap/scss/bootstrap";

Removed (no replacement)

  • $nested-kbd-font-weight
  • $enable-dark-mode — dark mode is always compiled
  • $enable-validation-icons
  • $enable-caret, $caret-width, $caret-vertical-align, $caret-spacing
  • $accordion-button-focus-border-color, $tooltip-arrow-color
  • $popover-arrow-color, $popover-arrow-outer-color
  • $alert-bg-scale, $alert-border-scale, $alert-color-scale
  • $list-group-item-bg-scale, $list-group-item-color-scale
  • $carousel-dark-indicator-active-bg, $carousel-dark-control-icon-filter
  • $dropdown-header-padding
  • All *-focus-box-shadow variables — use focus-ring() mixin with --focus-ring-* CSS custom properties
  • RFS mixins — use clamp() for responsive sizing
  • create-css-vars() mixin
  • Caret mixins (caret(), caret-down(), caret-up(), caret-end(), caret-start()) — add an icon to the toggle markup instead
  • muted, black-50, white-50 from text color utilities map

Utility API

Removed css-var, css-variable-name, and local-vars options. Use property map and variables instead.

Theme maps merge

$theme-colors, $theme-bgs, $theme-fgs, $theme-borders, $badge-variants, and other global maps use defaults(). Pass only the keys you want to change through @use ... with (). Set a key to null to drop it. Nested theme-color maps merge one level deep — pass the whole sub-map to change one role.

Root tokens emit on :root, :host. Repeat :root overrides on :host if you use shadow DOM.


Rebuilt behavior & new components

Beyond the renames above, several things changed how a v5 project behaves or what's available. Check the docs for full markup/options.

Carousel — rebuilt on CSS scroll-snap

The markup (.carousel → .carousel-inner → .carousel-item) and the JS API (next/prev/to/cycle/pause, slide/slid events) are preserved, but several things changed:

  • `ride` → `autoplay` (boolean, opt-in). data-bs-ride="carousel" becomes data-bs-autoplay="true"; { ride: 'carousel' } becomes { autoplay: true }. Default is autoplay: false, so a v5 carousel that auto-advanced now sits still until you opt in. Interacting with an autoplaying carousel now permanently stops it (WCAG 2.2.2).
  • `wrap` → `ends`. wrap: true → ends: "wrap" (or the new default "loop"); wrap: false → ends: "stop". Set via data-bs-ends. The touch option is removed (native scroll handles it).
  • Removed classes: .carousel-control-prev/next (compose a .btn-icon + data-bs-slide + .carousel-icon-prev/next), .carousel-caption (use your own markup), .carousel-dark (use data-bs-theme="dark"), .carousel-stacked (now the default), and the transitional .carousel-item-start/end/next/prev. Overlaid controls now require .carousel-overlay. Control-icon classes renamed .carousel-control-prev-icon → .carousel-icon-prev (and -next).

ScrollSpy — rebuilt on IntersectionObserver

The data-bs-spy="scroll" markup and the activate.bs.scrollspy event are unchanged, but detection is now driven by an activation line (no scroll-position polling), and the options changed:

  • Removed the deprecated `offset` and `method` options (deprecated since v5.1.3) — no longer parsed.
  • Added `topMargin` (default 12%) — positions the activation line as a % or px value from the top of the scroll root (e.g. 96px to sit below a sticky navbar). This is the everyday knob; use it instead of rootMargin.
  • `rootMargin` is now an advanced override (default null, was '0px 0px -25%'); when set it takes precedence over topMargin and is passed straight to the observer.
  • `threshold` default changed from [0.1, 0.5, 1] to [0].
  • With `smoothScroll`, clicking a link now restores the URL hash (history.replaceState) and moves focus to the target once the scroll settles (better keyboard/AT nav).
  • Target ids are resolved with getElementById, so ids with dots, colons, slashes, or percent-encoding work without manual escaping.

Collapse — simplified state and transitions

  • Remove selectors and tests that depend on .collapsing. Collapse now toggles .show and uses native size interpolation.
  • Replace trigger .collapsed selectors with [aria-expanded="false"].
  • Remove the toggle constructor option. Call show() or hide() when initialization must change state.

New components (didn't exist in v5)

ComponentTrigger / hookPurpose
Comboboxdata-bs-toggle="combobox"Filterable/autocomplete select built on Menu
Chip / Chip input.chip, .chip-input (data-bs-chips)Tags / tokens + interactive entry
Datepickerdata-bs-toggle="datepicker"Date picker (peer dep vanilla-calendar-pro)
Range.form-range (+ data-bs-bubble, ticks)Enhanced range slider with a value bubble
Strengthdata-bs-strengthPassword-strength meter
OTP inputdata-bs-otpOne-time-code input
Nav overflow.nav-overflow wrapper around a .navCollapses overflowing nav items into a menu
Togglerdata-bs-toggle="toggler"Generic class/attribute toggler
Submenu.submenu (within Menu)Nested menus (submenuTrigger, submenuDelay)
Stepper.stepperMulti-step workflow (CSS-only)
Avatar.avatarAvatars with sizes, status, .avatar-stack (CSS-only)
Form adorn.form-adornIcon/text decoration on inputs (CSS-only)
Prose.prose / .not-proseRich-typography scoping (CSS-only)

Removed / changed internals

  • `util/backdrop.js`, `util/focustrap.js`, and `util/scrollbar.js` removed. Dialog and Drawer use the native <dialog> element, which provides the backdrop (::backdrop), the focus trap, and an inert top layer; the body scroll-lock is now CSS (:root.dialog-open). If you imported bootstrap/js/src/util/backdrop, .../focustrap, or .../scrollbar directly, they're gone.
  • CSS `@layer`. Component styles are wrapped in cascade layers (colors, theme, config, root, reboot, layout, content, forms, components, custom, helpers, utilities). Author CSS outside any layer now wins over Bootstrap regardless of source order — if your v5 overrides relied on specificity or load order, re-check them.
  • `--bs--rgb variables removed.** The $-rgb` Sass vars and `--bs--rgb custom properties are gone. Replace rgba(var(--bs-primary-rgb), .5) with color-mix(in oklab, var(--bs-primary), transparent 50%)` (or use the color directly).

Step 6: Verify

  1. Build the project and fix any compilation errors.
  2. Search for remaining v5 patterns:
  • modal classes/attributes (should be dialog)
  • offcanvas (should be drawer)
  • dropdown (should be menu)
  • d-md-, d-lg-, col-md-, etc. (should use md: prefix syntax)
  • btn-primary, btn-outline- (should use .btn-solid .theme-*)
  • .text-primary, .text-danger (should be .fg-*)
  • @import in Sass (should be @use)
  • form-select (should be form-control)
  • was-validated, needs-validation (should be data-bs-validate)
  • popperConfig (should be floatingConfig)
  • form-check (should be check, radio, or switch)
  • var(--bs-*-rgb) / rgba(var(--bs-…-rgb) (removed — use color-mix())
  • $border-radius Sass vars (removed — use $radius / $radii / --radius-*)
  • child <svg> inside .btn-close (should be empty — icon is a CSS mask)
  • .btn-close-white (removed — set text color instead)
  • <div class="drawer"> (must be a native <dialog class="drawer">)
  • data-bs-ride (renamed to data-bs-autoplay); wrap: carousel option (now ends:)
  • .carousel-control-prev/next, .carousel-caption, .carousel-dark, .carousel-stacked (all removed)
  • .fs-1–.fs-6 (should be .fs-4xl … .fs-md)
  • .link-offset-* / .link-underline-* (now .underline-offset-* / .underline-*)
  • ScrollSpy offset / method options (removed — use topMargin)
  • inline SVG inside .check (icon is a CSS mask on the input)
  • $theme-colors full-map replacements (v6 merges via defaults())
  • .collapsing, .collapsed trigger selectors, and the Collapse toggle option
  • responsive stacks, CSS Grid, navbars, list groups, card groups, and stacked tables without a query container
  1. Test in browser — v6 requires support for oklch() and color-mix().
来自同一仓库

更多 Skills

全部 Skills