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.

  • bootstrap in der package.json auf die 6er-Version ziehen (derzeit 6.0.0-alpha.1).
  • @popperjs/core raus, @floating-ui/dom rein. 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 5Bootstrap 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 5Bootstrap 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 5Bootstrap 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 5Bootstrap 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 5Bootstrap 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 5Bootstrap 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-validationentfä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 5Wertgleicher Wert in Bootstrap 6
.p-20,5rem.p-3
.p-31rem.p-5
.p-41,5rem.p-7
.p-53rem.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 5Bootstrap 6
class="needs-validation" am <form>data-bs-validate am <form>
.was-validated per JavaScript setzenentfä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 5Bootstrap 6
<div class="accordion-item"><details class="accordion-item">
<h2 class="accordion-header"><summary class="accordion-header">
data-bs-parentname am <details>
.accordion-button, .accordion-collapseentfallen
data-bs-toggle="collapse", data-bs-targetentfallen

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.

BausteinWas 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.
SwitchEigener 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.
BreadcrumbDie 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-ButtonMarkup unverändert, aber das Icon ist eine CSS-Maske und nimmt currentcolor. .btn-close-white entfällt – stattdessen die Textfarbe setzen.
CardRahmen 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 5Bootstrap 6
Modal, Offcanvas, DropdownDialog, Drawer, Menu
popperConfig (Tooltip, Popover, Menü)floatingConfig
bootstrap.esm.js, bootstrap.esm.min.jsbootstrap.js
js/index.umd.jsentfällt
@types/bootstrapentfällt – die Typen liegen im Paket
jQuery-Unterstützungentfä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 5Bootstrap 6
_variables.scss_config.scss
_variables-dark.scssentfällt (jetzt in _theme.scss)
_maps.scssentfällt
_form-check.scss_check.scss, _radio.scss, _switch.scss
_placeholders.scss, _spinners.scss_placeholder.scss, _spinner.scss
mixins/_forms.scssmixins/_form-validation.scss
vendor/_rfs.scssentfällt – fließende Größen mit clamp()

Umbenannte Variablen und Funktionen

Bootstrap 5Bootstrap 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 5Bootstrap 6
data-bs-ride="carousel"data-bs-autoplay="true"
{ ride: 'carousel' }{ autoplay: true }
wrap: true / wrap: falseends: "wrap" / ends: "stop" (Vorgabe "loop")
.carousel-control-prev / -nextentfallen – selbst zusammensetzen aus .btn-icon, data-bs-slide und .carousel-icon-prev / -next
.carousel-captionentfällt
.carousel-darkdata-bs-theme="dark"
.carousel-item-start / -end / -next / -preventfallen
touch-Optionentfä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.

KomponenteAnker im Markup
Comboboxdata-bs-toggle="combobox"
Chip und Chip-Eingabe.chip, .chip-input, data-bs-chips
Datepickerdata-bs-toggle="datepicker"
Range mit Wertblase.form-range, data-bs-bubble
Passwortstärkedata-bs-strength
OTP-Eingabedata-bs-otp
Nav overflow.nav-overflow
Togglerdata-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-primary am Badge
  • Textfarben: text-primary und Geschwister, text-muted
  • window.bootstrap, popperConfig, needs-validation, was-validated
  • --bs-*-rgb und rgba( 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.