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>