25 KiB
Module and Theme Migration Guide to Bootstrap 5
Mandatory changes for modules to work with Bootstrap 5
- Classes extending
\humhub\modules\content\widgets\WallCreateContentForm
: replacerenderActiveForm(\humhub\modules\ui\form\widgets\ActiveForm $form)
withrenderActiveForm(\humhub\widgets\form\ActiveForm $form)
- "Dropdown" replacements in HTML attributes (see bellow)
Removed
humhub\widgets\ActiveForm
usehumhub\widgets\form\ActiveForm
insteadjs/humhub/legacy/jquery.loader.js
- CSS for User & Space picker
New
Widgets in these new folders:
humhub\widgets\bootstrap
humhub\widgets\form
humhub\widgets\modal
And especially:
humhub\widgets\bootstrap\Badge
(see https://getbootstrap.com/docs/5.3/components/badge/)humhub\widgets\bootstrap\Alert
(see https://getbootstrap.com/docs/5.3/components/alerts/)humhub\widgets\bootstrap\Button::asBadge()
humhub\widgets\bootstrap\Button::secondary()
humhub\widgets\bootstrap\Button::light()
humhub\widgets\bootstrap\Button::dark()
Colors: secondary
, light
and dark
are the new Bootstrap colors (default
is deprecated).
Deprecations
Bootstrap 3 components are removed from Bootstrap 5, but those used in HumHub are still supported for a while via the static/scss/_bootstrap3.scss
compatibility stylesheet
Widgets & helpers:
humhub\widgets\BootstrapComponent
humhub\widgets\Tabs
usehumhub\widgets\bootstrap\Tabs
insteadhumhub\widgets\Button
usehumhub\widgets\bootstrap\Button
insteadhumhub\widgets\Link
usehumhub\widgets\bootstrap\Link
insteadhumhub\widgets\Label
usehumhub\widgets\bootstrap\Badge
instead (watch out for class name changes!)humhub\modules\topic\widgets\TopicLabel
usehumhub\modules\topic\widgets\TopicBadge
instead (watch out for class name changes!)humhub\libs\Html
usehumhub\helpers\Html
instead
Widget methods & properties:
humhub\widgets\bootstrap\Button::xs()
usehumhub\widgets\bootstrap\Button::sm()
insteadhumhub\widgets\bootstrap\Button::defaultType()
usehumhub\widgets\bootstrap\Button::light()
orButton::secondary()
insteadhumhub\widgets\bootstrap\Badge::xs()
usehumhub\widgets\bootstrap\Badge::sm()
insteadhumhub\widgets\bootstrap\Badge::defaultType()
usehumhub\widgets\bootstrap\Badge::light()
orBadge::secondary()
insteadhumhub\widgets\bootstrap\Button::htmlOptions
usehumhub\widgets\bootstrap\Button::options
insteadhumhub\widgets\bootstrap\Badge::htmlOptions
usehumhub\widgets\bootstrap\Badge::options
instead
Name spaces starting with yii\bootstrap
: use yii\bootstrap5
instead (but see "HumHub widgets" bellow)
Forms and Modal Dialog: see bellow.
SCSS and CSS variables: see bellow.
HumHub widgets
If available, use HumHub widgets instead of the native library widgets. This will make it easier to migrate to new versions of the external libraries (see Code Style wiki page).
E.g. \yii\bootstrap5\Html
, use humhub\widgets\bootstrap\Html
instead.
If a Bootstrap widget is not available, create an issue on https://github.com/humhub/humhub/issues).
Modal Dialog
New
humhub\widgets\modal\ModalButton::outline()
(doc)
Deprecations
humhub\widgets\Modal
usehumhub\widgets\modal\JsModal
insteadhumhub\widgets\ModalDialog
usehumhub\widgets\modal\Modal
instead, which is different, as it's for the full Modal box, not just the dialog part of ithumhub\widgets\ModalButton
usehumhub\widgets\modal\ModalButton
insteadhumhub\widgets\modal\ModalButton::submitModal($url, $label)
usehumhub\widgets\modal\ModalButton::save($label, $url)
(watch out the parameter order change!) orhumhub\widgets\modal\ModalButton::primary($label)->submit($url)
insteadhumhub\widgets\ModalClose
usehumhub\widgets\modal\ModalClose
insteadhumhub\widgets\GlobalModal
usehumhub\widgets\modal\GlobalModal
insteadhumhub\widgets\GlobalConfirmModal
usehumhub\widgets\modal\GlobalConfirmModal
insteadhumhub\widgets\ModalDialog::begin()
usehumhub\widgets\modal\Modal::beginDialog()
instead (see changes in the "Modal Dialog" chapter bellow)humhub\widgets\ModalDialog::end()
usehumhub\widgets\modal\Modal::endDialog()
insteadhumhub\widgets\modal\Modal::header
&humhub\widgets\modal\JsModal::header
: usetitle
insteadhumhub\widgets\modal\Modal::animation
&humhub\widgets\modal\JsModal::animation
(all modal boxes are opened with the fade animation)humhub\widgets\modal\Modal::centerText
&humhub\widgets\modal\JsModal::centerText
humhub\widgets\modal\Modal::showClose
: usecloseButton
instead (but works differently, seeyii\bootstrap5\Modal::closeButton
doc)humhub\widgets\modal\JsModal::size
&humhub\widgets\modal\Modal::size
values: useModal::SIZE_DEFAULT
,Modal::SIZE_SMALL
,Modal::SIZE_LARGE
,Modal::SIZE_EXTRA_LARGE
instead of (normal
,extra-small
,small
,medium
, andlarge
)
Replacements in HTML attributes
data-backdrop
=>data-bs-backdrop
data-keyboard
=>data-bs-keyboard
Usage
Modal::beginDialog()
(formerly ModalDialog::begin()
) now includes <div class="modal-body">
and the footer must be defined as a parameter, similar to the header
which has been renamed to title
.
Before:
<?php ModalDialog::begin([
'header' => Yii::t('ModuleIdModule.base', 'Title'),
]) ?>
<div class="modal-body">
Content
</div>
<div class="modal-footer">
<?= ModalButton::cancel(Yii::t('base', 'Close')) ?>
</div>
<?php ModalDialog::end()?>
Now:
<?php Modal::beginDialog([
'title' => Yii::t('ModuleIdModule.base', 'Title'),
'footer' => ModalButton::cancel(Yii::t('base', 'Close')),
]) ?>
Content
<?php Modal::endDialog() ?>
If the footer contains a "Submit" button, the modal dialog must be included in the form by using the Modal::beginFormDialog()
and Modal::endFormDialog()
methods:
<?php $form = Modal::beginFormDialog([
'title' => Yii::t('ModuleIdModule.base', 'Title'),
'footer' => ModalButton::cancel() . ' ' . ModalButton::save(),
'form' => [], // configuration for the form (optional)
]) ?>
Content and the form inputs for $form
<?php Modal::endFormDialog()?>
Forms
Widgets deprecations
yii\widgets\ActiveForm
,yii\bootstrap\ActiveForm
,yii\bootstrap5\ActiveForm
,kartik\widgets\ActiveForm
,kartik\form\ActiveForm
,humhub\modules\ui\form\widgets\ActiveForm
: usehumhub\widgets\form\ActiveForm
insteadyii\widgets\ActiveField
,yii\bootstrap\ActiveField
,yii\bootstrap5\ActiveField
,humhub\modules\ui\form\widgets\ActiveField
: usehumhub\widgets\form\ActiveField
insteadhumhub\modules\ui\form\widgets\SortOrderField
usehumhub\widgets\form\SortOrderField
insteadhumhub\modules\ui\form\widgets\ContentHiddenCheckbox
usehumhub\widgets\form\ContentHiddenCheckbox
insteadhumhub\modules\ui\form\widgets\ContentVisibilitySelect
usehumhub\widgets\form\ContentVisibilitySelect
insteadhumhub\modules\ui\form\widgets\FormTabs
usehumhub\widgets\bootstrap\FormTabs
instead
Input groups
Remove <span class="input-group-btn">
button wrapper inside <div class="input-group">
.
Before:
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default">My action</button>
</span>
</div>
Now:
<div class="input-group">
<button class="btn btn-light">My action</button>
</div>
Error messages with RichTextField input widget
When using the RichTextField
input widget AND setting the form
attribute, as the active input is displayed as a nested input, the input elements mustn't be displayed twice.
Previously, the error field was displayed by the parent input.
But Bootstrap 5 requires the error field to be at the same level to the displayed input.
So now, the error HTML element (invalid-feedback
) is included in the widget.
Which means it needs to be removed in the parent input (by specifying the template) to prevent displaying it twice.
Example:
<?= $form->field($model, 'attribute', ['template' => "{label}\n{input}"])->widget(RichTextField::class, [
'form' => $form,
]) ?>
Dropdown, Navs & tabs
Dropdown
- Search for
dropdown-menu
in the code and add adropdown-header
class to header items, and adropdown-item
class to all link items (usuallya
andbutton
tags ; see documentation with example). - Search for
divider
classes (search regex expression for HTML tags:<\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?divider(?:\s[^"']*)?["'][^>]*>
), replace withdropdown-divider
, and move them to ahr
child tag ofli
. - Move the tags with
dropdown-header
class to a child tag ofli
(usually in ah6
tag) dropdown-menu-left
->dropdown-menu-start
dropdown-menu-right
->dropdown-menu-end
dropdown-menu float-start
->dropdown-menu dropdown-menu-start
dropdown-menu float-end
->dropdown-menu dropdown-menu-end
- Remove
<span class="caret"></span>
and<b class="caret"></b>
in dropdown buttons (as there are already added by Bootstrap 5 via the:after
pseudo-element)
Before:
<li class="dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
Dropdown button
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><h6>Dropdown header</h6></li>
<li role="separator" class="divider"></li>
<li><a href="#">Action</a></li>
</ul>
</li>
Now:
<div class="dropdown">
<button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Action</a></li>
</ul>
</li>
Navs & tabs
Make sure the required classes nav-item
and nav-link
exist in HTML tags about nav & tabs (see documentation with examples).
Search regex expression for HTML tags: <\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?nav(?:\s[^"']*)?["'][^>]*>
.
The active
class must be added to the nav-link
element (and not the nav-item
).
Example:
<ul class="nav">
<li class="nav-item">
<a class="nav-link active" href="#">Link</a>
</li>
...
</ul>
Tabs with Dropdown
Example:
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><hr class="dropdown-divider"></li>
</ul>
</li>
</ul>
Replacements in HTML attributes
These replacements must be done in PHP, SCSS (formerly LESS) and JS files.
General classes replacements
img-responsive
->img-fluid
(use thehumhub\modules\ui\widgets\BaseImage
widget when possible)alert-default
->alert-light
oralert-secondary
(use thehumhub\widgets\bootstrap\Alert
widget when possible)btn-xs
->btn-sm
(use thehumhub\widgets\bootstrap\Button
widget when possible)btn-default
->btn-light
(the newbtn-secondary
can also be used, but it will be a darker gray)pull-left
->float-start
pull-right
->float-end
center-block
->mx-auto
(image, inline or inline-block elements:d-block mx-auto
)text-left
->text-start
text-right
->text-end
btn-group-xs
->btn-group-sm
media-object img-rounded
->rounded
img-rounded
->rounded
data-toggle
->data-bs-toggle
data-target
->data-bs-target
data-dismiss
->data-bs-dismiss
no-space
->m-0 p-0
align-center
->text-center
ord-flex justify-content-center
input-group-addon
->input-group-text
(orinput-group-prepend
orinput-group-append
)form-group
->mb-3
well
(search regex expression for HTML tags:<\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?well(?:\s[^"']*)?["'][^>]*>
) ->bg-light p-3
for a simple inset container orcard
(with acard-body
child element)has-error
,has-warning
, andhas-success
->is-invalid
oris-valid
, but the new classes are now append to the input instead of the previousform-group
(the input is a child of the form group)help-block help-block-error
->invalid-feedback
help-block
->text-body-secondary
orform-text
if in a form- Remove
jumbotron
class
Columns with breakpoints
Bootstrap 3:
xs
: < 768pxsm
: ≥ 768pxmd
: ≥ 992pxlg
: ≥ 1200px
Bootstrap 5:
xs
: removed (default)sm
: ≥ 576px (new)md
: ≥ 768pxlg
: ≥ 992pxxl
: ≥ 1200pxxxl
: ≥ 1400px (new)
So replacements are (to be done in this order):
col-lg-
->col-xl-
col-md-
->col-lg-
col-sm-
->col-md-
col-xs-
->col-
Make sure:
- the parent element has the
row
class - the parent of parent the
container
class
Hidden/Visible elements
Use the new d-none
class instead of the display: none;
style (except for email views).
In the following class replacements, you can also use inline
, flex
, etc. instead of block
(depending on the desired display mode).
E.g., d-sm-inline
or d-sm-flex
instead of d-sm-block
.
In Bootstrap 3, the class applies to the designed screen size only, whereas in Bootstrap 5, the class applies to the designated screen size and larger.
And visible
will hide the element for other screen sizes, whereas in Bootstrap 5, you need to add d-none
to hide for other screen sizes.
Remplacement examples (must be adapted to the specific situation):
hidden-xs
->d-none d-sm-block
ord-none d-sm-inline
ord-none d-sm-flex
(depending on the desired display mode)hidden-sm
(hide on small screens only) →d-sm-none d-md-block
(hide on small screens, but show on medium or above ; idem, replaceblock
withinline
orflex
)hidden-md
(hide on medium screens only) →d-md-none d-lg-block
(hide on medium screens, but show on large or above)hidden-lg
(hide on large screens) →d-lg-none
(hide on large screens and above, including extra large screens which doesn't exist in Bootstrap 3)hidden
(search regex expression for HTML tags:<\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?hidden(?:\s[^"']*)?["'][^>]*>
; search also in JS for strings such asClass('hidden')
,Class("hidden")
,Class' => 'hidden'
) ->d-none
and othersvisible-xs
(hide on small screens and above) →d-block d-sm-none
ord-sm-none
if the element is visible by defaultvisible-sm
(visible on small screens only) →d-none d-sm-block d-md-none
(hide on all screens except small screens)visible-xs visible-sm
->d-md-none
(hide on large screens of above)visible-md
→d-none d-md-block d-lg-none
(show on medium screens only)visible-lg
→d-none d-lg-block
(show on large screens or above)visible-md visible-lg
->d-none d-md-block
(show on medium screens of above)visible
(search regex expression for HTML tags:<\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?visible(?:\s[^"']*)?["'][^>]*>
; search also in JS for strings such asClass('visible')
,Class("visible")
andClass' => 'visible'
) →d-block
JavaScript with d-none
In Bootstrap 5 CSS, the d-flex
class is set to flex !important
, and the d-none
class to display: none !important;
.
So, the jQuery hide()
and show()
functions won't work anymore, because of the !important
.
Replacements to do on these elements:
.hide()
->.addClass('d-none')
.show()
->.removeClass('d-none')
Spinners
Search for sk-
.
Before:
<div class="sk-spinner sk-spinner-three-bounce">
<div class="sk-bounce1"></div>
<div class="sk-bounce2"></div>
<div class="sk-bounce3"></div>
</div>
After, for a button:
<span class="spinner-border spinner-border-sm"></span>
After, in a container:
<div class="text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden"><?= Yii::t('base', 'Loading...') ?></span>
</div>
</div>
If wrapped in an HTML element having loader
(search for the <\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?loader(?:\s[^"']*)?["'][^>]*>
regex expression) or humhub-ui-loader
classes, replace the hole HTML code with the LoaderWidget
widget.
See documentation for more options and examples.
Panel
Should be replaced with cards.
TODO in core and to document here.
Label & Badge
Search for all label
classes (label label-
and the regex expression <\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?label(?:\s[^"']*)?["'][^>]*>
) and use the new humhub\widgets\bootstrap\Badge
widget instead
Use the humhub\widgets\bootstrap\Badge
widget when possible.
Replacements:
badge-default
->text-bg-light
ortext-bg-secondary
badge-primary
->text-bg-primary
badge-danger
->text-bg-danger
badge-warning
->text-bg-warning
badge-info
->text-bg-info
badge-success
->text-bg-success
Doc: https://getbootstrap.com/docs/5.3/components/badge/
Media
- Search for
media-list
and remove the HTML element, or, to keep a similar style, use the classhh-list
and replace theul
tag with adiv
. E.g.<ul class="media-list">
-><div class="hh-list">
- Inside, replace
li
tags withdiv
ora
tags. E.g.<li class="media">
-><div class="d-flex">
- Search for
media
classes (search regex expression for HTML tags:<\w+\s+[^>]*class\s*=\s*["'](?:[^"']*\s)?media(?:\s[^"']*)?["'][^>]*>
) and replace withd-flex
- Search for
img-space
classes and surround theUserImage
andSpaceImage
with theimg-profile-space
(see example inprotected/humhub/modules/content/widgets/views/wallEntry.php
) media-heading
->mt-0
(removes the top margin, keeping it close to the top of the content area) ; the related HTML tag can be replaced withh5
orh4
media-body
->flex-grow-1
media-left
->flex-shrink-0 me-2
media-right
->flex-shrink-0 ms-2 order-last
media-object
->flex-shrink-0
(if on an image, encapsulate the image in adiv
tag withflex-shrink-0
class)- Remove
float-start
(orpull-left
) class for images inside a<div class="flex-shrink-0">
Doc: https://getbootstrap.com/docs/5.3/utilities/flex/#media-object
Themes and Modules: LESS is replaced with SCSS
LESS format is not supported anymore. Use SCSS instead.
Doc: https://getbootstrap.com/docs/5.3/customize/sass/
Convert LESS to SCSS
Rename less
folder to scss
and rename all .less
files to .scss
Prefix all SCSS files with _
except the build.scss
and variables.scss
files.
E.g.: less/theme.less
-> scss/_theme.scss
Linux command: for file in *.less; do mv "$file" "_${file%.less}.scss"; done
and remove the _
for the build.scss
file
You can use the following tool to convert LESS to SCSS: https://less2scss.awk5.com/ However, you need to check the output manually, mainly functions and syntaxes such as:
color: fade(@color, 20%);
->color: rgba($color, 0.2);
transition:
: remove the@include
added after the conversion
An AI such as https://claude.ai/ might be more powerful to convert, but still requires manual checks.
SCSS and CSS variables
Changes
Deprecated SCSS variables:
$default
: use$light
instead$link
: use$link-color
instead
New SCSS variables:
$secondary
$light
$dark
CSS variable prefixes
Use the new variables starting with --bs-
for Bootstrap variables, and --hh-
for HumHub variables.
E.g.: color: $primary
-> color: var(--bs-primary)
Full deprecation list in static/scss/variables.scss
.
In modules or custom themes, if you need new variables, prefix them with --hh-xx-
where xx
is the first letters of your module or theme ID. E.g. my-module
will use hh-mm-
.
Use CSS variables instead of SCSS variables
In all SCSS files (except in SASS functions), replace all SCSS variables with CSS variables, when available (see list in variables.scss
), except the one used in SCSS function (e.g. lighten($primary, 5%)
). You can use regex:
- search:
\$([a-zA-Z0-9-_]+)
- replace:
var(--bs-$1)
(mainly for base colors such as$primary
) orvar(--hh-$1)
Root vs component variables
Root variables are global variables that can be used in any component.
They are stored in this file: _root.scss
See https://getbootstrap.com/docs/5.3/customize/css-variables/#root-variables
Component variables only apply to the HTML elements having the related class (e.g. .badge
for Badge CSS variables), and HTML elements inside of it.
Their values can be overwritten in the component related SCSS file (e.g. _badge.scss
). Example:
.badge {
--bs-badge-padding-x: 0.8em;
}
Full list of Bootstrap CSS variables here: https://github.com/twbs/bootstrap/tree/main/scss
Breakpoints
Search for @media
and replace with SCSS functions:
// X-Small devices (portrait phones and up)
// No media query necessary for xs breakpoint as it's effectively `@media (min-width: 0) { ... }`
// Small devices (landscape phones and up)
@include media-breakpoint-up(sm) { ... } // @media (min-width: 576px) { ... }
// Medium devices (tablets and up)
@include media-breakpoint-up(md) { ... } // @media (min-width: 768px) { ... }
// Large devices (desktops and up)
@include media-breakpoint-up(lg) { ... } // @media (min-width: 992px) { ... }
// X-Large devices (large desktops and up)
@include media-breakpoint-up(xl) { ... } // @media (min-width: 1200px) { ... }
// XX-Large devices (larger desktops)
@include media-breakpoint-up(xxl) { ... } // @media (min-width: 1400px) { ... }
It is also possible to use max-width
(should be occasionally used) using media-breakpoint-down
. E.g.:
// `sm` applies to x-small devices (portrait phones and down)
@include media-breakpoint-down(sm) { ... } // @media (max-width: 575.98px) { ... }
// `md` applies to small devices (landscape phones and down)
@include media-breakpoint-down(md) { ... } // @media (max-width: 767.98px) { ... }
// etc...
In modules, you will have to import the Boostrap breakpoints SCSS functions:
@import "../../../../vendor/bower-asset/bootstrap/scss/functions";
@import "../../../../vendor/bower-asset/bootstrap/scss/variables";
@import "../../../../vendor/bower-asset/bootstrap/scss/mixins/breakpoints";
Doc: https://getbootstrap.com/docs/5.3/layout/breakpoints
Select2 stylesheet
static/css/select2Theme
folder has been removed, and the SCSS file moved and renamed to static/scss/_select2.scss
Themes
Many styles have been refactored. Please review all your overwritten CSS selectors and values.
Build file
The build.scss
file mustn't import the parent theme files anymore, as it is automatically done by the new compiler.
Take example with the HumHub
community theme.
Compiler
Grunt compiler has been removed.
Instead, compile your theme with the web browser, using the new "(Re)build Theme CSS" button in Administration -> Settings -> Appearance.
If you use the "Updater" module to update HumHub core, you don't need to recompile your custom theme CSS anymore, as it will be done automatically.
But without this module, you will have to click on the "(Re)build Theme CSS" button after each HumHub core upgrade.
Overwritten view files
Most of the views have been refactored to use the new Bootstrap 5 HTML tags and classes.
Please review all overwritten view files. See Migration: Identify Template Changes wiki for more information.
The most important change concerns the protected/humhub/views/layouts/main.php
file, which has been refactored with bs5 flex logic (instead of floating right elements).
Documentation
- BS3 to BS4: https://getbootstrap.com/docs/4.6/migration/ and https://www.yiiframework.com/wiki/2556/yii2-upgrading-to-bootstrap-4
- BS4 to BS5: https://getbootstrap.com/docs/5.3/migration/ and https://github.com/humhub/yii2-bootstrap5/blob/master/docs/guide/migrating-yii2-bootstrap.md
- BS3 to BS5: https://nodebb.org/blog/nodebb-specific-bootstrap-3-to-5-migration-guide/