Part of Real-World CoreUI Migration: From Laravel 8 to Laravel 11
Since this project kept c- prefixed layout classes from CoreUI, it needed a custom compatibility layer for Bootstrap 4 utility classes that were removed or renamed in Bootstrap 5:
// components/_layout.scss
// Styles for migration Bootstrap 4 to 5
// Bootstrap 4 spacing utilities removed in BS5
@media (min-width: 768px) {
.mr-md-auto, .mx-md-auto {
margin-right: auto !important;
}
.text-md-right {
margin-top: -15px;
padding-right: 15px;
}
}
// Bootstrap 4 form classes removed in BS5
.form-group {
margin-bottom: 1rem;
}
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
.form-row {
display: flex;
flex-wrap: wrap;
margin-right: -5px;
margin-left: -5px;
}
.form-row > .col {
padding-left: 5px;
padding-right: 5px;
}
label {
margin-bottom: 0.5rem;
}
// Bootstrap 4 utility classes renamed in BS5
.font-weight-bold {
font-weight: 700 !important;
}
// Bootstrap 4 bg- classes that changed behavior
.bg-dark {
background-color: #636f83 !important;
line-height: 1.5;
}
.bg-secondary {
background-color: #ced2d8 !important;
}
.btn-outline-secondary {
border-color: #ced2d8;
color: #ced2d8;
}
Bootstrap 4→5 class rename reference for Blade templates:
| Bootstrap 4 | Bootstrap 5 | Status in This Project |
|---|---|---|
mr-*, ml-* |
me-*, ms-* |
Kept BS4 via compatibility CSS |
pr-*, pl-* |
pe-*, ps-* |
Kept BS4 via compatibility CSS |
text-right |
text-end |
Kept BS4 via compatibility CSS |
text-left |
text-start |
Kept BS4 via compatibility CSS |
float-right |
float-end |
Kept BS4 via compatibility CSS |
font-weight-bold |
fw-bold |
Kept BS4 via compatibility CSS |
form-group |
Removed | Re-implemented via SCSS |
form-inline |
Removed | Re-implemented via SCSS |
form-row |
row + g-* gutter |
Re-implemented via SCSS |
data-toggle |
data-bs-toggle |
Kept BS4 (legacy JS bundle) |
data-target |
data-bs-target |
Kept BS4 (legacy JS bundle) |
data-dismiss |
data-bs-dismiss |
Kept BS4 (legacy JS bundle) |
jumbotron |
Removed | Kept via custom SCSS |
JavaScript Component Changes
CoreUI 3's JavaScript was tightly coupled to jQuery-compatible patterns. CoreUI 5 drops jQuery dependency entirely:
// CoreUI 3 — sidebar initialization was automatic via coreui.bundle.js
// The bundle handled Perfect Scrollbar, event delegation, and state management
// Just include the script and it "works":
// <script src="{{ mix('js/app.js') }}"></script>
// CoreUI 5 — this project opted for vanilla JS sidebar management:
// resources/js/scripts/sidebar.js
if (document.querySelector('.c-sidebar')) {
let sidebar = document.querySelector('.c-sidebar');
// Persist sidebar state across page loads via localStorage
if (localStorage.getItem("vktoggle") === "1") {
sidebar.classList.add('c-sidebar-show');
} else {
sidebar.classList.remove('c-sidebar-show');
}
// Minimizer button (collapse sidebar to icons let sidebarMinimizer = document.querySelector('.c-sidebar-minimizer');
if (sidebarMinimizer) {
sidebarMinimizer.addEventListener('click', () => {
sidebar.classList.remove('c-sidebar-show');
localStorage.setItem("vktoggle", "0");
});
}
// Hamburger toggle button (mobile and desktop)
let sidebarTogglers = [].slice.call(
document.querySelectorAll('.sidebar-toggler')
);
sidebarTogglers.map(togglerEl => {
togglerEl.addEventListener('click', () => {
if (sidebar.classList.contains('c-sidebar-show')) {
sidebar.classList.remove('c-sidebar-show');
localStorage.setItem("vktoggle", "0");
} else {
sidebar.classList.add('c-sidebar-show');
localStorage.setItem("vktoggle", "1");
}
});
});
}
Passive Event Listener Requirement
CoreUI 5 (and modern Chrome) enforces passive event listeners for touch/scroll events. The legacy app.js bundle triggers violations without this workaround:
<!-- Added to admin layout <head> to prevent console warnings -->
<script>
const originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
if (['touchstart', 'touchmove', 'wheel', 'mousewheel'].includes(type)) {
options = options || {};
if (typeof options === 'object') {
options.passive = options.passive !== undefined ? options.passive : true;
}
}
return originalAddEventListener.call(this, type, listener, options);
};
</script>