--- name: bootstrap-v5-v6-migration description: Migrate projects from Bootstrap 5 to Bootstrap 6. Use when upgrading from Bootstrap 5, migrating v5 to v6, or updating v5 class names, components, Sass, or JavaScript to the latest version. For Bootstrap 4 projects, start with the v4-to-v6 migration skill instead. guide: /guides/migration --- # 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](https://getbootstrap.com/docs/6.0/customize/sass/#compile-time-overrides). 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}` | v5 | v6 | | --- | --- | | `.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 | Scope | v5 | v6 | | --- | --- | --- | | 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 attrs | `data-bs-toggle="modal"`, `data-bs-dismiss="modal"` | `data-bs-toggle="dialog"`, `data-bs-dismiss="dialog"` | | JS export | `Modal` | `Dialog` | | Events | `*.bs.modal` | `*.bs.dialog` | | CSS vars | `--modal-*` | `--dialog-*` | | Body class | `.modal-open` on `
` | `.dialog-open` on `` | Remove `.modal-dialog` and `.modal-content` wrappers entirely — see Step 3. #### Offcanvas -> Drawer | Scope | v5 | v6 | | --- | --- | --- | | Classes | `.offcanvas`, `.offcanvas-start/end/top/bottom/header/body/title` | `.drawer`, `.drawer-start/end/top/bottom/header/body/title` | | Data attrs | `data-bs-toggle="offcanvas"`, `data-bs-dismiss="offcanvas"` | `data-bs-toggle="drawer"`, `data-bs-dismiss="drawer"` | | JS export | `Offcanvas` | `Drawer` | | Events | `*.bs.offcanvas` | `*.bs.drawer` | | CSS vars | `--offcanvas-*` | `--drawer-*` | | Sass | `$zindex-offcanvas` | `$zindex-drawer` | #### Dropdown -> Menu | Scope | v5 | v6 | | --- | --- | --- | | Classes | `.dropdown-menu`, `.dropdown-item`, `.dropdown-divider`, `.dropdown-header` | `.menu`, `.menu-item`, `.menu-divider`, `.menu-header` | | Data attrs | `data-bs-toggle="dropdown"` | `data-bs-toggle="menu"` | | JS export | `Dropdown` | `Menu` | | 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. | v5 | v6 | | --- | --- | | `.btn-primary` | `class="btn-solid theme-primary"` | | `.btn-outline-primary` | `class="btn-outline theme-primary"` | | `.alert-primary` | `class="alert theme-primary"` | | `.badge.bg-primary` | `class="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 | v5 | v6 | | --- | --- | | `.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 `