Upgrading to Release 2026.3

Migrate custom templates, UI extensions, and JavaScript from Bootstrap 3 to Bootstrap 5 for Cloud Management Platform (CMP) Release 2026.3.51

Who this affects

This page applies to you if you maintain any of the following:

  • Custom Django templates in /var/opt/cloudbolt/proserv/ that extend base.html or any CMP template
  • UI extensions (XUIs) you wrote yourself, or modified after installing
  • Custom JavaScript that calls c2.* functions

CloudBolt UI extensions

CloudBolt UI extensions have been updated for Bootstrap 5 and republished in the Content Library. If an updated version is not listed yet, refresh the Library listing.

  • If you have not modified the extension, re-import it from the Library. You do not need the rest of this page.
  • If you modified the extension after installing it, re-importing replaces your copy, and you cannot recover your changes. Either back up your copy, re-import, and reapply your changes using this page, or migrate your copy in place using this page.

What changed

Bootstrap 5 renamed or removed almost all of the Bootstrap 3 class names and data attributes. This means:

  • Markup that uses them renders as unstyled elements.
  • Interactive widgets built with legacy data-* attributes do not open, close, or switch.

Check whether your templates need to be updated

Run these read-only checks on the appliance. Test any changes on a staging appliance before applying them in production.

1. Find template blocks that no longer exist

grep -rnE '\{% *block +(breadcrumbs|extrastyle|fluidclass|outercontent|scripts) *%\}' /var/opt/cloudbolt/proserv/

Each match is a block override that is silently discarded and must be renamed. See Template blocks that no longer exist.

2. Find Bootstrap 3 markup

grep -rniE 'panel-default|panel-heading|panel-body|panel-footer|control-label|btn-default|form-horizontal|form-group|data-toggle=|data-target=|data-dismiss=|data-placement=|pull-left|pull-right|col-xs-|img-responsive|center-block|help-block|input-group-addon|table-condensed|glyphicon|hidden-(xs|sm|md|lg)|visible-(xs|sm|md|lg)|sr-only|\bwell\b|\b(mr|ml|pr|pl)-[0-5]\b' /var/opt/cloudbolt/proserv/

Review each match against the class mapping and data attributes tables. Most of these no longer function and must be migrated. Five of them still work, as described in the class mapping.

The check also catches the Bootstrap 4 spacing utilities mr-*, ml-*, pr-*, and pl-*, which Bootstrap 5 renamed.

3. Dashboard UI extensions only: find renamed card classes

Run this check only if you maintain a UI extension that renders as a dashboard widget.

grep -rnE 'card-heading|card-default' /var/opt/cloudbolt/proserv/

Update any matches in your stylesheet or JavaScript. See Dashboard UI extensions.

Template blocks that no longer exist

While your {% extends %} line continues to work, the old page shell defined five blocks that the new one does not: breadcrumbs, extrastyle, fluidclass, outercontent, and scripts.

In Django, a child template can override only blocks its parent chain defines. Content is discarded without warning if you override a name the parent does not have. The page renders without the block’s contents.

Rename each override to its Bootstrap 5 equivalent:

No longer exists Use instead Notes
extrastyle head Put <link rel="stylesheet"> and <style> tags here. Do not use inlinecss, which is already inside a <style> element.
scripts body_scripts Renders just before </body>, in the same place as the old block. Unlike the old block, it already contains CMP code that shows server messages and runs the c2script and onReady blocks. Start your override with {{ block.super }} to retain that code.
outercontent content CMP adds the surrounding page layout. Include only your own content.
breadcrumbs breadcrumb-item This block is already inside a <li class="breadcrumb-item active"> element. Include only the current page name, without <ol> or <li> tags.
fluidclass No equivalent CMP sets the page width. Remove the override.

Class mapping

Use this table to replace Bootstrap 3 classes.

Bootstrap 3 classes btn-default, form-horizontal, help-block, well, and the glyphicon icon font continue to function. The CMP stylesheet defines them in Bootstrap 5 terms because the CMP UI uses them. They are not scheduled for removal, so updating them is optional but recommended.

Bootstrap 3 Bootstrap 5 Notes
panel panel-default card Also replace panel-heading with card-header, panel-body with card-body, and panel-footer with card-footer.
Bootstrap 3’s panel carried a bottom margin, and Bootstrap 5’s card does not. Add mb-3 wherever panels were stacked, or they sit flush against each other.
For tab and dashboard extensions, read Tabbed UI extensions or Dashboard UI extensions first.
panel-title Remove Style the heading element directly.
control-label form-label
form-group mb-3 Bootstrap 5 removed this class.
form-horizontal row and col-* on each field Bootstrap 5 removed horizontal forms. form-horizontal still works.
help-block form-text help-block still works.
btn-default btn-light Matches the rest of the CMP interface and uses the portal’s button theme. btn-default still works.
cb-btn / cb-btn-primary btn btn-sm / btn-primary Legacy CMP classes. cb-btn-primary does not use the portal’s primary color. cb-btn is a small button, so add btn-sm to keep the size.
btn-xs btn-sm Bootstrap 5 has no extra-small size.
input-group-addon input-group-text Place it directly inside .input-group, and remove any .input-group-btn wrapper.
pull-left / pull-right float-start / float-end
text-left / text-right text-start / text-end
mr-* / ml-* (Bootstrap 4) me-* / ms-* Bootstrap 5 renamed left and right to start and end, and the old names do nothing. Replace pr-* and pl-* with pe-* and ps-*. mt-*, mb-*, pt-*, and pb-* are unchanged.
col-xs-N col-N The class without a size prefix is now the smallest size.
hidden-xs, visible-sm, and similar d-none, d-sm-block, and similar There is no one-to-one replacement. Check each case.
hidden d-none
sr-only visually-hidden
img-responsive img-fluid
center-block mx-auto d-block
table-condensed table-sm
label label-default badge text-bg-secondary Replace other label-* classes with the matching text-bg-* class.
badge (rounded) badge rounded-pill Bootstrap 5 badges are square by default.
well card card-body Or bg-body-secondary p-3 rounded. well still works.
caret Remove dropdown-toggle adds its own arrow.
close (modal close button) btn-close Remove the &times; content.
glyphicon glyphicon-* Bootstrap Icons or Font Awesome Glyphicons still work. For new work, use the same icons as the surrounding CMP pages.
icon-* (CloudBolt legacy icons) bi bi-* (Bootstrap Icons) A temporary compatibility layer maps some names to Bootstrap Icons, such as icon-edit, icon-delete, icon-add, and icon-verify-connection. It does not cover every name. For example, icon-sync displays nothing. Replace icon-* classes when you edit the markup.

Data attributes

Bootstrap 5 adds bs- to every Bootstrap data attribute and ignores the old names, so a modal with data-toggle="modal" does not open.

Bootstrap 3 Bootstrap 5
data-toggle data-bs-toggle
data-target data-bs-target
data-dismiss data-bs-dismiss
data-placement data-bs-placement
data-parent data-bs-parent
data-ride, data-slide, data-slide-to, data-spy The matching data-bs-* attribute

Components that need more than a rename

Tabs and pills

In Bootstrap 5, the active class moves from the <li> to the link; the link needs the nav-link class, and each pane needs role="tabpanel".

Bootstrap 3:

<ul class="nav nav-tabs">
  <li class="active"><a href="#one" data-toggle="tab">One</a></li>
  <li><a href="#two" data-toggle="tab">Two</a></li>
</ul>
<div class="tab-content">
  <div class="tab-pane active" id="one">First</div>
  <div class="tab-pane" id="two">Second</div>
</div>

Bootstrap 5:

<ul class="nav nav-tabs" role="tablist">
  <li class="nav-item" role="presentation">
    <button class="nav-link active" type="button" role="tab"
            data-bs-toggle="tab" data-bs-target="#one"
            aria-controls="one" aria-selected="true">One</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" type="button" role="tab"
            data-bs-toggle="tab" data-bs-target="#two"
            aria-controls="two" aria-selected="false">Two</button>
  </li>
</ul>
<div class="tab-content">
  <div class="tab-pane fade show active" id="one" role="tabpanel">First</div>
  <div class="tab-pane fade" id="two" role="tabpanel">Second</div>
</div>

Modals

The modal markup is unchanged. Update the trigger attributes and the close button, which no longer needs &times;:

<!-- Bootstrap 3 -->
<button data-toggle="modal" data-target="#mymodal">Open</button>
<button class="close" data-dismiss="modal">&times;</button>

<!-- Bootstrap 5 -->
<button data-bs-toggle="modal" data-bs-target="#mymodal">Open</button>
<button class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>

Accordions

Rewrite Bootstrap 3 accordions (panel-group with collapse) using the Bootstrap 5 accordion component, with accordion-item, accordion-header, accordion-button, and accordion-collapse.

Forms

Replace form-group with mb-3, control-label with form-label, and help-block with form-text:

<!-- Bootstrap 3 -->
<div class="form-group">
  <label class="control-label">Name</label>
  <input type="text" class="form-control">
  <span class="help-block">Helper text</span>
</div>

<!-- Bootstrap 5 -->
<div class="mb-3">
  <label class="form-label">Name</label>
  <input type="text" class="form-control">
  <div class="form-text">Helper text</div>
</div>

Dark mode

The CMP interface has a dark theme, and Bootstrap 3 markup often assumes a light background. When you migrate:

  • Do not use bg-light, text-bg-light, or bg-white. They stay light in dark mode, which makes text unreadable. Use bg-body-secondary instead, and var(--fg-1) if you need to set the text color.
  • Do not hard-code hex colors for backgrounds, borders, or text. Use Bootstrap utility classes or CMP CSS custom properties.

Check each migrated page in both the light and dark themes.

JavaScript changes

If your code calls c2.* functions, check it against the following lists.

Removed modules

These modules no longer exist. Calling them causes a TypeError:

Renamed functions

These still work under their old names:

  • c2.tooltip is now an alias for c2.tooltips. closeAll was removed. init works differently:

    • It only finds elements with data-bs-toggle="tooltip". Elements that still use data-toggle get no tooltip.
    • It only applies to elements already on the page. Call it again after you add content.

    For new code, use c2.tooltips.init(selector).

  • The server statistics chart functions moved to c2.chartsServerStats, and are still available on c2.charts. c2.charts.pie and c2.charts.bar are unchanged.

Removed functions

These functions were removed with no replacement:

Module Removed functions
c2.accessibility alert, alertAll
c2.blueprints initCatalog, initFilters
c2.charts buildGroupBillingBarSeries, buildServerBillingSeries, serverPieChartDefaults
c2.commonEventHandlers aceOnPanelOpen, aceOffPanelOpen, popovers
c2.dataTables dialogDefaults, isDataTable
c2.forms appendShowAllButton, hide_add_link_when_depleted, moveOffsetLabelsToLeftCol, splitElementsIntoColumns
c2.orchestrationActions init

The removed c2.charts functions are not available in c2.chartsServerStats either.

What to use instead

Previously Now
c2.datepicker, c2.datetimepicker Nothing. Pickers now work from the markup. See Date and time picker.
Scripting Bootstrap components The Bootstrap 5 classes directly: bootstrap.Modal, bootstrap.Tab, bootstrap.Tooltip, bootstrap.Dropdown, bootstrap.Toast, and bootstrap.Popover.
Switching tabs c2.tabs.activate(hash), including the leading # (for example, "#build"). You do not need to call c2.tabs.init(), which runs on page load.

Date and time picker

Date and time pickers work without code changes:

  • Inputs with the render_as_datepicker or render_as_datetimepicker class still get a picker. By default, values use the YYYY-MM-DD and YYYY-MM-DD HH:mm:ss formats, so server-side parsing is unchanged.
  • Pickers start on page load, and also on content added later, such as forms loaded with AJAX.
  • Existing $(input).datepicker(options) and $(input).datetimepicker(options) calls still work.

In new code:

  • To start a picker, call $(input).bs5DateTimePicker(options).
  • To start pickers in part of the page, call $.bs5DateTimePicker.autoInit(element).
  • To set options on an input, use attributes such as data-format, data-include-time, data-min-date, and data-max-date.

Tabbed UI extensions

CMP displays a tab UI extension (built with TabGroup or {% draw_tabs %}) inside a frame that is already styled as a card, with a background, border, rounded corners, shadow, and padding.

Do not wrap the whole tab pane in a card, or the pane gets a double border. Mapping panel panel-default to card causes this. If a Bootstrap 3 tab used one panel around the whole pane, remove the panel and change the panel-heading text to a heading:

<!-- Bootstrap 3 -->
<div class="panel panel-default">
  <div class="panel-heading">Jobs</div>
  <div class="panel-body"><table class="table">...</table></div>
</div>

<!-- Bootstrap 5: the tab body is already the card -->
<h5 class="mb-3">Jobs</h5>
<table class="table">...</table>

Use cards inside a pane only to separate sections. If a pane had two or three stacked panels, change them to two or three cards, each with mb-3.

Dashboard UI extensions

CMP displays a dashboard UI extension inside a widget frame. To avoid showing a card inside a card, CMP unwraps the first element with the card class in your extension’s HTML, even if it is nested inside other elements:

  1. CMP removes the card’s .card-header and shows its .card-title and .card-subtitle in the widget header.
  2. CMP moves the elements inside .card-body into the widget body. Text that is not inside an element is lost.
  3. CMP deletes the card, including anything else inside it, such as a .card-footer.

What you need to do depends on whether your extension extends dashboard/card.html:

  • If it does, you do not need to change your markup. The template now uses card and card-header instead of card card-default and card-heading. Update any of your own CSS or JavaScript that uses the old class names. Run the dashboard check to find them.
  • If it does not, CMP treats the first card in your HTML as the widget frame. To keep your card, give it a different class.

As in earlier releases, CMP also:

  • Moves elements with the modal class to the end of the page, so modals open over the page instead of inside the widget.
  • Re-creates <script> elements so that they run.

Verify your work

  1. Open the browser console on each page. Errors such as bootstrap is not defined or an undefined c2 function point to code that needs to be migrated. Fix the first error before checking the others.
  2. Open every modal, tab, dropdown, collapse, and tooltip. These fail without a console error if an attribute was missed.
  3. Confirm your stylesheets and scripts load in the browser’s network panel. A missing file can mean a template block was not renamed.
  4. Check each page in light and dark mode.
  5. Check each tab extension for a double border. A double border means a card is wrapping the pane.
  6. Check each dashboard widget extension on the dashboard, not only on its own page. Its title should appear in the widget header, with no empty card frame around the content.
  7. Check that every icon displays. A gap usually means an icon-* name that the compatibility layer does not cover.
  8. Run the checks again. The block check should return nothing. The class check should return only the five classes that still work, or matches you chose to keep.

Getting help

If a page still does not display correctly, contact CloudBolt Support by emailing support@cloudbolt.io, raising a support ticket, or contacting your Technical Account Manager. Include the template source and screenshots of the page in light and dark mode.