Von Bootstrap 5 auf Bootstrap 6
Vier grundlegende Änderungen – alles andere folgt daraus
Bootstrap 6 ist kein Punkt-Update. Vier Dinge ändern sich von Grund auf, der größte Teil der Arbeit folgt daraus.
Breakpoint-Präfixe wandern nach vorn. Aus .d-md-none wird .md:d-none. Das betrifft jede responsive Utility-Klasse im Projekt und ist mit Abstand der größte Posten der Umstellung. xxl heißt jetzt 2xl.
Farbvarianten werden zu Theme-Tokens. Form und Farbe stehen getrennt: statt .btn-primary jetzt .btn-solid theme-primary. Dasselbe Muster bei Alerts und Badges.
Drei Komponenten bauen auf nativem HTML auf. Modal und Offcanvas heißen Dialog und Drawer und sind echte <dialog>-Elemente, das Accordion ist <details>/<summary> und braucht kein JavaScript mehr. Dropdown heißt Menu.
JavaScript nur noch als ES-Modul. Die UMD-Bundles, das globale window.bootstrap und die jQuery-Unterstützung sind weg.
Die Abschnitte darunter gehen den Weg in der Reihenfolge, in der am wenigsten schiefgeht: erst der Build, dann die Klassen, dann das Markup, dann der Code. Nach jedem Schritt lohnt eine Suche im ganzen Projekt nach den alten Mustern – die meisten Fehler sind übersehene Reste, keine falschen Entscheidungen.
Die Umstellung in sieben Schritten
Schritt 1: Abhängigkeiten und Build
Zuerst die Abhängigkeiten, sonst baut nichts übersetzbar durch.
bootstrapin derpackage.jsonauf die 6er-Version ziehen (derzeit6.0.0-alpha.1).@popperjs/coreraus,@floating-ui/domrein. Tooltip, Popover und Menu positionieren jetzt mit Floating UI.- Nur für den neuen Datepicker zusätzlich
vanilla-calendar-pro– eine Peer-Abhängigkeit, die Bootstrap nicht selbst mitbringt.
Im eigenen Sass wird aus dem Import ein @use:
// vorher
@import "bootstrap/scss/bootstrap";
// jetzt
@use "bootstrap/scss/bootstrap";Das ist mehr als eine Schreibweise: @use lädt eine Datei genau einmal und kapselt ihren Namensraum. Bootstraps Variablen stehen danach nicht mehr automatisch global zur Verfügung – wer sie lesen will, holt sie über den Namensraum oder gibt eigene Werte beim Laden mit (@use "…" with (…)). Reihenfolge und Konfiguration des eigenen Themes muss man dabei einmal sauber sortieren.
Schritt 2: Klassen und Attribute umbenennen
Der Breakpoint steht nicht mehr im Klassennamen, sondern davor, getrennt durch einen Doppelpunkt. Statt für jede Utility eine eigene Regel zu kennen, gilt ein Muster: <breakpoint>:<klasse>. Dasselbe für Zustände (hover:) und Medien (print:). xxl heißt 2xl.
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.d-md-none | .md:d-none |
.p-lg-3 | .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 |
.modal-fullscreen-sm-down | .sm-down:dialog-fullscreen |
.d-print-none | .print:d-none |
.opacity-50-hover | .hover:opacity-50 |
Das ist der Posten, der in einem gewachsenen Projekt die meisten Treffer hat. Eine Suche nach -sm-, -md-, -lg-, -xl- und -xxl- findet die Stellen – im Markup wie in Fluid-Templates und in JavaScript, das Klassen setzt.
Drei Komponenten heißen anders, und zwar durchgehend: Klasse, Daten-Attribut, JavaScript-Export, Event-Name und CSS-Variable. Wer nur die Klassen tauscht, lässt die halbe Umstellung liegen.
Modal → Dialog
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.modal | .dialog |
.modal-header, -body, -footer, -title | .dialog-header, -body, -footer, -title |
.modal-sm, -lg, -xl, -fullscreen | .dialog-sm, -lg, -xl, -fullscreen |
data-bs-toggle="modal", data-bs-dismiss="modal" | …="dialog" |
Modal (JS) | Dialog |
*.bs.modal | *.bs.dialog |
--modal-* | --dialog-* |
.modal-open am <body> | .dialog-open am <html> |
Offcanvas → Drawer
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.offcanvas | .drawer |
.offcanvas-start, -end, -top, -bottom | .drawer-start, -end, -top, -bottom |
.offcanvas-header, -body, -title | .drawer-header, -body, -title |
data-bs-toggle="offcanvas", data-bs-dismiss="offcanvas" | …="drawer" |
Offcanvas (JS) | Drawer |
*.bs.offcanvas | *.bs.drawer |
--offcanvas-* | --drawer-* |
$zindex-offcanvas | $zindex-drawer |
Dropdown → Menu
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.dropdown-menu | .menu |
.dropdown-item | .menu-item |
.dropdown-divider | .menu-divider |
.dropdown-header | .menu-header |
data-bs-toggle="dropdown" | data-bs-toggle="menu" |
Dropdown (JS) | Menu |
*.bs.dropdown | *.bs.menu |
$zindex-dropdown | $zindex-menu |
Beim Menü fällt zusätzlich Markup weg – der umschließende .dropdown und .dropdown-toggle gibt es nicht mehr. Das steht in Schritt 3.
Die Farbvariante steckt nicht mehr im Komponentennamen. Eine Klasse bestimmt die Form, ein Theme-Token die Farbe – damit lässt sich dieselbe Farbe über Button, Alert und Badge hinweg einheitlich setzen.
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.btn-primary | .btn-solid theme-primary |
.btn-outline-primary | .btn-outline theme-primary |
.alert-primary | .alert theme-primary |
.badge.bg-primary | .badge theme-primary |
Dasselbe gilt für jede andere Variante – secondary, success, info, warning, danger. .theme-light und .theme-dark gibt es nicht; helles und dunkles Erscheinungsbild läuft über das Color Scheme, nicht über eine Variante.
Umbenannte Utilities
| Bootstrap 5 | Bootstrap 6 |
|---|---|
.text-primary, .text-danger, … | .fg-primary, .fg-danger, … |
.text-muted | .fg-secondary |
.text-bg-primary | .bg-primary fg-contrast-primary |
.mh-*, .mw-* | .max-h-*, .max-w-* |
.form-select | .form-control (auch am <select>) |
.clearfix | .d-flow-root |
.lh-base | .lh-md |
.link-offset-* | .underline-offset-* |
.link-underline-* | .underline-* |
.has-validation | entfällt |
Die Umbenennung von .text-* auf .fg-* betrifft nur die Textfarben. Ausrichtung und Größe bleiben, wo sie waren: .text-center und .text-nowrap heißen weiter so. Bei .placeholder-glow und .placeholder-pulse genauso – glow bleibt als Alias erhalten.
Schriftgrößen
Aus den Nummern werden T-Shirt-Größen: .fs-1 bis .fs-6 heißen jetzt .fs-4xl, .fs-3xl, .fs-2xl, .fs-xl, .fs-lg, .fs-md – in dieser Reihenfolge, die größte zuerst. Ab lg aufwärts sind die Größen fließend, skalieren also mit der Viewport-Breite statt in Stufen.
Abstands-Skala
Die Skala hat feinere Stufen bekommen, und die alten Schlüssel stehen jetzt für andere Werte. Wer den Wert behalten will, muss die Zahl ändern:
| Bootstrap 5 | Wert | gleicher Wert in Bootstrap 6 |
|---|---|---|
.p-2 | 0,5rem | .p-3 |
.p-3 | 1rem | .p-5 |
.p-4 | 1,5rem | .p-7 |
.p-5 | 3rem | .p-12 |
Gilt für alle Abstands-Utilities, also auch m-*, px-*, gap-* und g-*. .p-1 und .p-0 bleiben, wie sie waren. Wer die Klassen unverändert übernimmt, bekommt kein kaputtes Layout, aber ein deutlich engeres – das ist der Punkt, an dem eine Seite nach der Migration „irgendwie anders“ aussieht. Negative Margins gibt es nur noch für einige wenige Klassen.
Formular-Validierung
| Bootstrap 5 | Bootstrap 6 |
|---|---|
class="needs-validation" am <form> | data-bs-validate am <form> |
.was-validated per JavaScript setzen | entfällt – Bootstrap regelt den Zustand selbst |
<div class="valid-tooltip"> | <div class="tooltip valid-tooltip"> |
<div class="invalid-tooltip"> | <div class="tooltip invalid-tooltip"> |
Schritt 3: HTML-Struktur
Bei diesen Komponenten reicht Suchen und Ersetzen nicht – sie bekommen anderes Markup, meist weniger davon.
Dialog (früher Modal)
Ein einziges natives <dialog class="dialog"> ersetzt die drei verschachtelten div. .modal-dialog und .modal-content entfallen, Kopf, Rumpf und Fuß liegen jetzt direkt im <dialog>. Das Overlay kommt von ::backdrop, der Fokus bleibt vom Browser aus im Dialog.
Drawer (früher Offcanvas)
Auch der Drawer muss ein <dialog> sein – ein div mit der Klasse funktioniert nicht. In der Navbar ersetzt er den Collapse: aus data-bs-toggle="collapse" wird data-bs-toggle="drawer", aus .collapse.navbar-collapse ein <dialog class="drawer"> mit .drawer-header und .drawer-body. .navbar-light und .navbar-dark gibt es nicht mehr.
Accordion
Kein JavaScript mehr, sondern <details> und <summary>:
| Bootstrap 5 | Bootstrap 6 |
|---|---|
<div class="accordion-item"> | <details class="accordion-item"> |
<h2 class="accordion-header"> | <summary class="accordion-header"> |
data-bs-parent | name am <details> |
.accordion-button, .accordion-collapse | entfallen |
data-bs-toggle="collapse", data-bs-target | entfallen |
Neu dazu: .accordion-icon für ein eigenes SVG im <summary>, .accordion-sm und .accordion-gap. Dass nur ein Eintrag offen bleibt, regelt das gleiche name an allen <details> – wie bei Radio-Buttons.
Menü (früher Dropdown)
Der umschließende .dropdown fällt weg, .dropdown-toggle und .dropdown-toggle-split ebenso. Die Liste wird flach: aus <ul><li><a> wird <div class="menu"> mit <a class="menu-item"> darin.
| Baustein | Was sich ändert |
|---|---|
| Checkbox | .form-check wird .form-field, die Klasse am Eingabefeld heißt .check (bzw. .radio). .form-check-label entfällt, das Inline-SVG im Häkchen ebenso. |
| Switch | Eigener Baustein: Wrapper .switch, role="switch" und das Attribut switch am <input>. |
| Toggle-Button | .btn-check wandert vom <input> an das <label>, das Eingabefeld liegt darin. Das Paar aus id und for entfällt damit. |
| Range | .form-range gehört an einen umschließenden <div>, das Eingabefeld bekommt .form-range-input. |
| Breadcrumb | Die Links brauchen .breadcrumb-link, die Trenner sind keine ::before-Pseudoelemente mehr, sondern leere <li class="breadcrumb-divider">. .active sitzt am Link, nicht am <li>. |
| Close-Button | Markup unverändert, aber das Icon ist eine CSS-Maske und nimmt currentcolor. .btn-close-white entfällt – stattdessen die Textfarbe setzen. |
| Card | Rahmen und Innenaufbau sind anders. .card-link entfällt (normale Links mit Flex- oder Gap-Utilities), .card-title und .card-text bringen keine eigenen Stile mehr mit. Die waagerechte Karte heißt .card-row, Kartengruppen brauchen .contains-inline am Elternelement. Neu: .card-subtle und .card-translucent. |
Schritt 4: JavaScript
Bootstrap 6 liefert ausschließlich ES-Module. Die UMD-Bundles sind weg, und mit ihnen das globale window.bootstrap – wer eine Komponente braucht, importiert sie.
<!-- vorher -->
<script src="bootstrap.bundle.min.js"></script>
<script>new bootstrap.Tooltip(el);</script>
<!-- jetzt -->
<script type="module">
import { Tooltip } from './bootstrap.bundle.min.js';
new Tooltip(el);
</script>| Bootstrap 5 | Bootstrap 6 |
|---|---|
Modal, Offcanvas, Dropdown | Dialog, Drawer, Menu |
popperConfig (Tooltip, Popover, Menü) | floatingConfig |
bootstrap.esm.js, bootstrap.esm.min.js | bootstrap.js |
js/index.umd.js | entfällt |
@types/bootstrap | entfällt – die Typen liegen im Paket |
| jQuery-Unterstützung | entfällt |
Lebenszyklus-Methoden geben ein Promise zurück
show(), hide(), toggle() und close() lassen sich jetzt awaiten. Wer bisher auf shown.bs.* oder hidden.bs.* gewartet hat, kommt ohne Listener aus – die Events gibt es weiterhin, sie werden nur seltener gebraucht.
// vorher
el.addEventListener('shown.bs.modal', () => { /* … */ });
modal.show();
// jetzt
await dialog.show();
/* … */Validierung
Der Selektor ändert sich von .needs-validation auf form[data-bs-validate], und die Zeile, die was-validated setzt, kann raus.
Schritt 5: Sass
Wer Bootstrap nur einbindet, kann diesen Schritt überspringen. Wer eigenes Sass darüber baut, hat hier die meiste Arbeit – und sie fällt beim ersten Build auf, nicht erst im Browser.
Umbenannte und entfallene Dateien
| Bootstrap 5 | Bootstrap 6 |
|---|---|
_variables.scss | _config.scss |
_variables-dark.scss | entfällt (jetzt in _theme.scss) |
_maps.scss | entfällt |
_form-check.scss | _check.scss, _radio.scss, _switch.scss |
_placeholders.scss, _spinners.scss | _placeholder.scss, _spinner.scss |
mixins/_forms.scss | mixins/_form-validation.scss |
vendor/_rfs.scss | entfällt – fließende Größen mit clamp() |
Umbenannte Variablen und Funktionen
| Bootstrap 5 | Bootstrap 6 |
|---|---|
$grid-breakpoints | $breakpoints |
$zindex-dropdown, $zindex-offcanvas | $zindex-menu, $zindex-drawer |
$form-validation-states | $validation-states |
$hr-bg-color, $hr-height | $hr-border-color, $hr-border-width |
add(), subtract() | calc() |
breakpoint-infix() | breakpoint-prefix() – liefert "md\:", nicht "-md" |
$border-radius und die -sm/-lg/-xl/-xxl/-pill-Reihe | $radius, die Map $radii, --radius-0 bis --radius-9, --radius-pill |
.rounded-1, .rounded-3 | .rounded-3, .rounded-5 |
Ohne Ersatz entfallen
Eine ganze Reihe von Schaltern und Variablen ist weg, weil die Sache jetzt anders gelöst wird: die caret-Variablen und -Mixins, alle *-focus-box-shadow-Variablen (dafür focus-ring() und --focus-ring-*), die *-scale-Variablen von Alert und List-Group, $enable-dark-mode, $enable-validation-icons, $enable-negative-margins, die RFS-Mixins und create-css-vars(). Die vollständige Liste steht im Original – der Build nennt sie aber auch von selbst.
Utility-API und Theme-Maps
In der Utility-API sind die Optionen css-var, css-variable-name und local-vars entfallen; stattdessen beschreibt man das über property und variables. Die globalen Maps – $theme-colors und Verwandte – werden nicht mehr komplett ersetzt, sondern mit defaults() teilweise überschrieben. Ein Schlüssel auf null entfernt ihn.
Keine -rgb-Variablen mehr
Die $*-rgb-Variablen und die --bs-*-rgb-Eigenschaften gibt es nicht mehr. Transparenz läuft über color-mix():
// vorher
background: rgba(var(--bs-primary-rgb), .5);
// jetzt
background: color-mix(in oklab, var(--bs-primary), transparent 50%);Neu gebaut und neu dazu
Drei Komponenten heißen gleich, arbeiten aber anders. Hier ändert sich nicht nur Markup, sondern das Verhalten – auch dort, wo man nichts angepasst hat.
Carousel: jetzt auf CSS-Scroll-Snap
| Bootstrap 5 | Bootstrap 6 |
|---|---|
data-bs-ride="carousel" | data-bs-autoplay="true" |
{ ride: 'carousel' } | { autoplay: true } |
wrap: true / wrap: false | ends: "wrap" / ends: "stop" (Vorgabe "loop") |
.carousel-control-prev / -next | entfallen – selbst zusammensetzen aus .btn-icon, data-bs-slide und .carousel-icon-prev / -next |
.carousel-caption | entfällt |
.carousel-dark | data-bs-theme="dark" |
.carousel-item-start / -end / -next / -prev | entfallen |
touch-Option | entfällt |
Das Wichtigste daran: Autoplay ist jetzt abgeschaltet, solange man es nicht ausdrücklich einschaltet. Ein Carousel, das vorher von selbst lief, steht nach der Migration still. Überlagerte Bedienelemente brauchen zusätzlich .carousel-overlay.
ScrollSpy: jetzt auf IntersectionObserver
Die Optionen offset und method gibt es nicht mehr. An ihre Stelle tritt topMargin (Vorgabe 12 %), rootMargin bleibt als Feineinstellung für Sonderfälle. Die Standard-Schwelle ist jetzt [0].
Collapse: weniger Zustände
.collapsing ist weg, die toggle-Option ebenso – stattdessen show() oder hide() aufrufen. Eigenes CSS, das am Zustand des Auslösers hängt, läuft nicht mehr über .collapsed, sondern über [aria-expanded="false"].
Interna, die verschwunden sind
Backdrop, Fokus-Falle und Scrollbar-Hilfe braucht Bootstrap nicht mehr selbst: das übernehmen ::backdrop, das native <dialog> und :root.dialog-open. Das CSS nutzt @layer – eigene Regeln außerhalb einer Ebene gewinnen damit leichter als früher.
Nichts davon muss man bei der Migration anfassen – aber einiges löst selbstgebaute Lösungen ab, die man loswerden kann.
| Komponente | Anker im Markup |
|---|---|
| Combobox | data-bs-toggle="combobox" |
| Chip und Chip-Eingabe | .chip, .chip-input, data-bs-chips |
| Datepicker | data-bs-toggle="datepicker" |
| Range mit Wertblase | .form-range, data-bs-bubble |
| Passwortstärke | data-bs-strength |
| OTP-Eingabe | data-bs-otp |
| Nav overflow | .nav-overflow |
| Toggler | data-bs-toggle="toggler" |
| Untermenü | .submenu, Optionen submenuTrigger, submenuDelay |
| Stepper | .stepper |
| Avatar | .avatar, .avatar-stack |
| Form adorn | .form-adorn |
| Prose | .prose, .not-prose |
Zu den meisten dieser Komponenten gibt es auf dieser Demo-Seite ein eigenes Beispiel.
Schritt 6: Prüfen
Zum Schluss einmal durchbauen – Sass meldet die meisten Reste von selbst, weil umbenannte Variablen und Funktionen den Build abbrechen. Was der Build nicht sieht, findet eine Suche im Projekt:
- responsive Klassen in alter Schreibweise:
-sm-,-md-,-lg-,-xl-,-xxl- - die alten Komponentennamen:
modal,offcanvas,dropdown– in Klassen, Attributen, Events und Importen - Varianten in alter Form:
btn-primary,alert-primary,bg-primaryam Badge - Textfarben:
text-primaryund Geschwister,text-muted window.bootstrap,popperConfig,needs-validation,was-validated--bs-*-rgbundrgba(in eigenem CSS
Nicht nur im HTML suchen: Fluid-Templates, TypoScript, eigene Sass-Dateien und JavaScript, das Klassen setzt, tragen genauso viele Treffer.
Im Browser nachsehen
Bootstrap 6 setzt moderne CSS-Funktionen voraus – unter anderem oklch() und color-mix(). Zum Testen also ein Browser, der beides kennt; in älteren sehen Farben falsch aus oder fehlen ganz. Wer eine Browser-Matrix bedienen muss, klärt das besser vor der Migration als danach.
Und das, was keine Suche findet: Abstände. Durch die neue Abstands-Skala wirken übernommene Klassen enger als vorher. Einmal über die wichtigen Seiten gehen und vergleichen lohnt sich.
Quelle und Hinweis
Grundlage dieser Seite ist die Migrationsanleitung im Bootstrap-Repository: skills/bootstrap-v5-v6-migration/SKILL.md in twbs/bootstrap (MIT-Lizenz). Die Zuordnungen alt → neu stammen von dort; Aufbau und Text dieser Seite sind eine eigene deutsche Fassung, keine Übersetzung Wort für Wort. Verbindlich ist immer das Original – Bootstrap 6 steht noch im Alpha-Stadium, Namen und Vorgaben können sich bis zur fertigen Version ändern.
Diese Seite beschreibt die Umstellung von Bootstrap selbst. Was davon EXT:t3sbootstrap übernimmt und was die Extension für dich erledigt, steht im Changelog der Extension.