# 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

---

Site [llms.txt](/llms.txt)

---

<div class="alert alert-info" role="alert">


[Release 2026.3.51](/docs/cmp/about/releases/release-2026-3/#release-2026-3-51) moves the Cloud Management Platform (CMP) interface from Bootstrap 3 to Bootstrap 5. Bootstrap 3 is no longer supported, and no compatibility layer is provided. This page covers what changed and how to migrate custom templates, UI extensions, and JavaScript.
</div>


## 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](/docs/cmp/use/catalog/content-library/). If an updated version is not listed yet, [refresh the Library listing](/docs/cmp/use/catalog/content-library/#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

```bash
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](#template-blocks-that-no-longer-exist).

### 2. Find Bootstrap 3 markup

```bash
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](#class-mapping) and [data attributes](#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 {#find-renamed-card-classes}

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

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

Update any matches in your stylesheet or JavaScript. See [Dashboard UI extensions](#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. |

<div class="alert alert-info" role="alert">


Only top-level overrides of these names are discarded. A block with one of these names still renders if it is inside a block that exists, such as `{% block content %}`.
</div>


## 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`.<br>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.<br>For tab and dashboard extensions, read [Tabbed UI extensions](#tabbed-ui-extensions) or [Dashboard UI extensions](#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 |

<div class="alert alert-warning" role="alert">


Rename only Bootstrap attributes. Do not rename your own `data-*` attributes, or CMP attributes such as `data-tooltip-source`.
</div>


## 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:

```html
<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:

```html
<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;`:

```html
<!-- 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`:

```html
<!-- 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`:

- `c2.animation`
- `c2.cui`
- `c2.datepicker` (see [Date and time picker](#date-and-time-picker))
- `c2.datetimepicker` (see [Date and time picker](#date-and-time-picker))
- `c2.iframes`
- `c2.progressBars`
- `c2.quickSetup`
- `c2.scrolling`
- `c2.text`
- `c2.topology`
- `c2.visibility`

<div class="alert alert-warning" role="alert">


A `TypeError` also stops any later scripts on the page from running. In the browser console, fix the first error before checking the others.
</div>


### 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](#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:

```html
<!-- 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](#find-renamed-card-classes) 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.

<div class="alert alert-warning" role="alert">


Scripts inside a `.modal` do not run, because CMP moves modals before it re-creates scripts. Keep widget scripts outside modals.
</div>


## 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](#check-whether-your-templates-need-to-be-updated) 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](/docs/cmp/support/) by emailing [support@cloudbolt.io](mailto:support@cloudbolt.io), [raising a support ticket](https://support.cloudbolt.io/cloudbolt/s/contactsupport), or contacting your Technical Account Manager. Include the template source and screenshots of the page in light and dark mode.

## Related

- [Front-end assets and tools](/docs/cmp/developer-resources/ui-extensions/front-end-assets-and-tools/): The libraries loaded by default, and how to ship your own CSS and JavaScript.
- [UI elements that support extensions](/docs/cmp/developer-resources/ui-extensions/supported-elements/): The decorator and arguments for each extension type.
- [Upgrading to Release 2026.2](/docs/cmp/configure/administration/maintain/upgrade/release-2026-2/): Django 5.2 and Python 3.12 changes that also affect UI extensions.
