diff --git a/skills/bootstrap-v5-v6-migration/SKILL.md b/skills/bootstrap-v5-v6-migration/SKILL.md new file mode 100644 index 000000000000..56ab128c9413 --- /dev/null +++ b/skills/bootstrap-v5-v6-migration/SKILL.md @@ -0,0 +1,490 @@ +--- +name: bootstrap-v5-v6-migration +description: Migrate projects from Bootstrap 5 to Bootstrap 6. Use when upgrading Bootstrap, migrating v5 to v6, or updating Bootstrap class names, components, Sass, or JavaScript to the latest version. +--- + +# Bootstrap v5 to v6 Migration + +## Workflow + +Work through each phase in order. After each phase, search the codebase for remaining v5 patterns before moving on. + +- [ ] Phase 1: Update dependencies and build setup +- [ ] Phase 2: Rename CSS classes and data attributes +- [ ] Phase 3: Restructure component HTML +- [ ] Phase 4: Update JavaScript +- [ ] Phase 5: Update Sass +- [ ] Phase 6: Verify + +--- + +## Phase 1: Dependencies & Build + +1. Update `package.json`: `"bootstrap": "^6.0.0"` +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) + +```scss +// v5 +@import "bootstrap/scss/bootstrap"; + +// v6 +@use "bootstrap/scss/bootstrap"; + +// v6 with overrides +@use "bootstrap/scss/bootstrap" with ( + $spacer: 1rem +); +``` + +--- + +## Phase 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` | + +### 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 Phase 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 Phase 3 for new markup. + +### Button & badge variants -> theme tokens + +Per-color classes are replaced by variant + `.theme-*` composition. Apply to all colors (`primary`, `secondary`, `success`, `danger`, `warning`, `info`, `light`, `dark`). + +| v5 | v6 | +|---|---| +| `.btn-primary` | `.btn-solid .theme-primary` | +| `.btn-outline-primary` | `.btn-outline .theme-primary` | +| `.alert-primary` | `.alert .theme-primary` | +| `.badge.bg-primary` | `.badge-subtle .theme-primary` | + +New button variants: `.btn-solid`, `.btn-outline`, `.btn-subtle`, `.btn-text`, `.btn-styled`, `.btn-link`. + +### 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 ` + + + + +
+
+ + + + + +
+ +
+``` + +Radio and switch equivalents: + +```html + +
+ + +
+ + +
+
+ +
+ +
+``` + +### Toggle buttons + +Input is now nested inside the label. `.btn-check` goes on the label. No `id`/`for` needed. + +```html + + + + + + +``` + +### Breadcrumbs + +Add `.breadcrumb-link` on `` elements. Add `.breadcrumb-divider` separator elements between items (replaces `::before` pseudo-elements). + +```html + + + + + +``` + +--- + +## Phase 4: JavaScript + +### ESM-only + +All dist files are now ES modules. No more UMD bundles or `window.bootstrap` global. + +```html + + + + + +``` + +Replace global namespace access with imports: + +```js +// v5 +const tooltip = bootstrap.Tooltip.getOrCreateInstance(el) + +// v6 +import { Tooltip } from './bootstrap.bundle.min.js' +const tooltip = Tooltip.getOrCreateInstance(el) +``` + +Data attribute APIs (`data-bs-toggle`, etc.) are unchanged — just add `type="module"` to the script tag. Bundler imports (`import { X } from 'bootstrap'`) work as before. + +### Renamed JS exports + +| v5 | v6 | +|---|---| +| `Modal` | `Dialog` | +| `Offcanvas` | `Drawer` | +| `Dropdown` | `Menu` | + +### Popper -> Floating UI + +Replace `@popperjs/core` with `@floating-ui/dom`. Rename the `popperConfig` option to `floatingConfig` on Tooltip, Popover, and Menu. + +### 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 +``` + +--- + +## Phase 5: Sass + +### Renamed files + +| v5 | v6 | +|---|---| +| `_variables.scss` | `_config.scss` | +| `_variables-dark.scss` | Removed (merged into `_theme.scss`) | +| `_maps.scss` | Removed | +| `_placeholders.scss` | `_placeholder.scss` | +| `_spinners.scss` | `_spinner.scss` | +| `_form-check.scss` | `_checkbox.scss`, `_radio.scss`, `_switch.scss` | +| `mixins/_forms.scss` | `mixins/_form-validation.scss` | +| `forms/_form-variables.scss` | Removed | +| `vendor/_rfs.scss` | Removed | + +### Renamed variables and functions + +| v5 | v6 | +|---|---| +| `$grid-breakpoints` | `$breakpoints` | +| `$border-radius-xxl` | `$border-radius-2xl` | +| `$text-muted` | Use 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-filter` | `$btn-close-filter-dark` | +| `add()` / `subtract()` | `calc()` | +| `breakpoint-infix()` | `breakpoint-prefix()` (returns `"md\:"` not `"-md"`) | +| `$infix` (in loop mixins) | `$prefix` | +| `$prefix` (CSS var prefix) | Removed — use PostCSS instead | + +### Removed (no replacement) + +- `$nested-kbd-font-weight` +- `$enable-validation-icons` +- `$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-caption-color`, `$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 +- `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. + +--- + +## Phase 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`) +3. Test in browser — v6 requires support for `oklch()` and `color-mix()`.