A Plone 6 theme based on Bootstrap 6 and Barceloneta (Classic UI).
Project description
plonetheme.bootstrap6
[!NOTE] The package name
plonetheme.bootstrap6is a working title and is still open for discussion. The final name may change before any stable release.
A Plone 6.2 Classic UI theme based on Bootstrap 6.
[!WARNING] This theme is under active development and not yet production-ready. It depends on Bootstrap 6, which is currently in alpha and subject to breaking changes without notice. The Bootstrap 6 alpha API — including configuration variables, mixins, and class names — may change in any future alpha or beta release. Do not use this theme in production environments.
Overview
plonetheme.bootstrap6 is a Diazo-based Plone theme that brings Bootstrap 6 to the Plone Classic UI. Unlike Barceloneta (Bootstrap 5), it uses Bootstrap 6's native @use/@forward Sass module system and its standard breakpoints. Whether this theme becomes the basis for Plone 7's Classic UI is an idea currently under evaluation.
Key characteristics:
- Bootstrap 6 alpha (docs,
twbs/bootstrap#v6-dev) with native@use/@forwardSass module system — no deprecated@import - Plone Classic UI compatible — uses the same HTML selectors as Barceloneta (
#content-header,#portal-globalnav-wrapper,#portal-column-content, etc.) - Dark mode support via Bootstrap 6 color-mode system (
@media (prefers-color-scheme: dark)) - Standard Bootstrap 6 breakpoints (
lg: 1024px,xl: 1280px,2xl: 1536px) — no barceloneta backports - CSS custom properties for Plone colors (
--plone-link,--plone-state-*) without a vendor prefix (Bootstrap 6 dropped--bs-)
Requirements
| Dependency | Version |
|---|---|
| Plone | ≥ 6.2 |
| plone.app.theming | any |
| Python | ≥ 3.10 |
| Node.js / pnpm | for SCSS builds only |
Installation
Python package
Add plonetheme.bootstrap6 to your Plone instance's install_requires or buildout eggs:
[instance]
eggs +=
plonetheme.bootstrap6
Then activate the theme in the Plone control panel under Site Setup → Theming, or via a Generic Setup profile that depends on this package.
Activate via Generic Setup
The included profiles/default profile sets the active theme automatically when applied:
<!-- profiles/default/metadata.xml -->
<dependencies>
<dependency>profile-plonetheme.bootstrap6:default</dependency>
</dependencies>
SCSS Structure
The theme is built from a set of modular SCSS files inside scss/. Bootstrap 6 requires that its configuration variables are set before the first @use "bootstrap/scss/..." call — this is handled centrally in _bs-forward.scss.
scss/
├── _bs-forward.scss # Bootstrap 6 config + forward (must be first)
├── _bs5-compat.scss # Bootstrap 5 → 6 compatibility shim (see below)
├── _noto.scss # Noto Sans web-font face declarations
├── _plone-colors.scss # Plone brand colors and state color maps
├── _plone-root.scss # CSS custom properties emitted on :root
├── _roboto.scss # Roboto web-font face declarations
├── bootstrap6.scss # Main entry point (compiled to CSS)
└── plone/
├── _scaffolding.scss # Base layout, skip nav, link colors
├── _header.scss # #content-header, logo, livesearch
├── _sitenav.scss # .navbar-bootstrap6, dropdowns, offcanvas
├── _toolbar.scss # #edit-bar (Classic UI edit toolbar)
├── _breadcrumbs.scss # #above-content-wrapper
├── _content.scss # Column layout, #content, related items
├── _portlets.scss # .portletWrapper, .portlet, navigation portlet
├── _forms.scss # .field, form widgets, login, search
└── _footer.scss # #portal-footer-wrapper, doormat, site-actions
Key Bootstrap 6 differences from barceloneta (Bootstrap 5)
| Topic | Bootstrap 5 (barceloneta) | Bootstrap 6 (bootstrap6) |
|---|---|---|
| Sass API | @import (global namespace) |
@use / @forward (module-scoped) |
| Configuration | $var !default; before @import |
@use "config" with ($var: value) |
| Variable files | _variables.scss, _variables-dark.scss |
_config.scss, _colors.scss, _theme.scss |
| CSS variable prefix | --bs-body-bg |
--body-bg (no prefix) |
| Color functions | darken() / lighten() |
color.adjust() via @use "sass:color" |
| Z-index names | $zindex-dropdown, $zindex-offcanvas |
$zindex-menu, $zindex-drawer |
Breakpoint lg / xl / xxl |
992px / 1200px / 1400px |
1024px / 1280px / 1536px (standard BS6; xxl renamed to 2xl) |
| Color system | HSL | oklch |
RFS / font-size() mixin |
present | removed |
Bootstrap 5 Compatibility Shim
Plone Classic UI templates were written against Bootstrap 5. Several component names changed in Bootstrap 6. The file scss/_bs5-compat.scss bridges the gap so that existing templates render correctly without modification.
[!NOTE] This shim is a transitional measure. It will be removed once the upstream Plone templates have been updated to Bootstrap 6 class names. To remove it, delete the
@use "bs5-compat"line inscss/bootstrap6.scss.
Covered components
Dropdown → Menu
Bootstrap 6 renamed the dropdown component to menu.
| BS5 class | BS6 equivalent | Notes |
|---|---|---|
.dropdown |
.dropdown |
unchanged (position wrapper) |
.dropdown-toggle |
— | caret re-added via ::after in shim |
.dropdown-menu |
.menu |
full style set, uses BS6 CSS variables |
.dropdown-item |
.menu-item |
hover / active / disabled states |
.dropdown-header |
.menu-header |
section label |
.dropdown-divider |
.menu-divider |
horizontal rule |
.dropdown-menu-end |
— | right-align alias |
.dropdown-menu-md-end |
— | responsive right-align |
JavaScript note: data-bs-toggle="dropdown" must be changed to data-bs-toggle="menu" in templates once the Bootstrap 6 JS bundle is active. The shim covers the CSS side only.
Button color variants
Bootstrap 6 replaced the colour-named button classes with a functional modifier system (btn-solid, btn-outline, …) driven by --theme-* CSS custom properties. The shim re-introduces the old names by setting the --btn-* variables that the base .btn rule reads.
| BS5 class | BS6 approach | Shim |
|---|---|---|
.btn-primary |
.btn.btn-solid + --theme-*: var(--primary-*) |
✓ |
.btn-secondary |
.btn.btn-solid + --theme-*: var(--secondary-*) |
✓ |
.btn-success |
.btn.btn-solid + --theme-*: var(--success-*) |
✓ |
.btn-danger |
.btn.btn-solid + --theme-*: var(--danger-*) |
✓ |
.btn-warning |
.btn.btn-solid + --theme-*: var(--warning-*) |
✓ |
.btn-info |
.btn.btn-solid + --theme-*: var(--info-*) |
✓ |
.btn-light / .btn-dark |
.btn.btn-subtle / .btn.btn-solid |
✓ |
.btn-outline-{color} |
.btn.btn-outline + --theme-* |
✓ (all 8 variants) |
Unchanged classes (btn, btn-sm, btn-lg, btn-link) still exist natively in Bootstrap 6 and do not need the shim.
Directional dropdown containers
Bootstrap 6 removed .dropend / .dropstart / .dropup. Side-opening menus now use data-bs-placement. The shim restores positioning and caret styles for the old class names.
| BS5 class | Notes |
|---|---|
.dropend |
submenu opens inline-end (right in LTR); right-pointing caret |
.dropstart |
submenu opens inline-start (left in LTR); left-pointing caret |
.dropup |
submenu opens upward |
Offcanvas → Drawer
Bootstrap 6 replaced the offcanvas panel with a native <dialog>-based drawer component. Plone Classic UI uses Bootstrap 5 offcanvas for the mobile navigation panel (see #offcanvasNavbar in index.html) and Bootstrap 5 JS controls the .show state.
| BS5 class | BS6 equivalent | Notes |
|---|---|---|
.offcanvas |
.drawer |
position, slide-in, visibility toggle via .show |
.offcanvas-end |
.drawer-end |
slides in from the right |
.offcanvas-start |
.drawer-start |
slides in from the left |
.offcanvas-top |
.drawer-top |
slides in from the top |
.offcanvas-bottom |
.drawer-bottom |
slides in from the bottom |
.offcanvas-header |
.drawer-header |
header row with close button |
.offcanvas-title |
.drawer-title |
title text |
.offcanvas-body |
.drawer-body |
scrollable content area |
.offcanvas-backdrop |
::backdrop (native) |
semi-transparent overlay; .show triggers visibility |
At the navbar-expand-{bp} breakpoint the offcanvas is shown inline (always visible, no slide-in), matching Bootstrap 5 navbar behaviour.
Modal → Dialog
Bootstrap 6 replaced the .modal component with the native <dialog> element styled via .dialog-*. Mockup's pat-plone-modal pattern (data-pat-plone-modal / .pat-plone-modal) still generates Bootstrap 5 .modal HTML (plain <div> elements, not <dialog>). This shim re-introduces all .modal-* CSS using Bootstrap 6 design tokens.
| BS5 class | BS6 equivalent | Notes |
|---|---|---|
.modal |
.dialog |
full-viewport container; .show triggers visibility |
.modal-backdrop |
::backdrop (native) |
.show and .backdrop-active supported (Mockup uses the latter) |
.modal-dialog |
— | no inner wrapper in BS6; replicated for Mockup's <div> structure |
.modal-content |
.dialog directly |
styled card; uses BS6 --border-color-translucent, --radius-7, --box-shadow-lg |
.modal-header |
.dialog-header |
title + close button row |
.modal-title |
.dialog-title |
heading text |
.modal-body |
.dialog-body |
main content area |
.modal-footer |
.dialog-footer |
action button row |
.modal-sm / .modal-lg / .modal-xl |
.dialog-sm / .dialog-lg / .dialog-xl |
width variants |
.modal-fullscreen |
.dialog-fullscreen |
full-viewport variant |
.modal-dialog-centered |
native (dialog centres via margin: auto) |
replicated for <div> structure |
.modal-dialog-scrollable |
— | scrollable body variant |
body.modal-open |
.dialog-open |
prevents background scroll while open |
Mockup note: pat-plone-modal adds .backdrop-active (not .show) to its backdrop element. The shim accepts both.
Responsive utility classes — breakpoint-infix format
Bootstrap 6 moved the breakpoint from an infix to a prefix:
| BS5 pattern | BS6 pattern | Example |
|---|---|---|
.d-{bp}-{val} |
.{bp}\:d-{val} |
.d-lg-flex → .lg\:d-flex |
.flex-{bp}-{dir} |
.{bp}\:flex-{dir} |
.flex-lg-row |
.align-items-{bp}-{val} |
.{bp}\:align-items-{val} |
.align-items-lg-center |
.justify-content-{bp}-{val} |
.{bp}\:justify-content-{val} |
— |
.order-{bp}-{n} |
.{bp}\:order-{n} |
— |
.text-{bp}-{align} |
.{bp}\:text-{align} |
.text-lg-center |
.float-{bp}-{dir} |
.{bp}\:float-{dir} |
.float-md-end |
The shim regenerates all of the above for breakpoints sm, md, lg, xl.
Navbar expand — .navbar-expand-{bp}
Bootstrap 6 renamed .navbar-expand-lg to .lg\:navbar-expand. The shim restores the old infix class for sm, md, lg, xl, covering the flex layout switch (horizontal nav items, hidden toggler) above the breakpoint. The offcanvas inline-display override is part of the Offcanvas section.
Misc removed / changed classes
| BS5 class | Status in BS6 | Shim behaviour |
|---|---|---|
.text-muted |
removed | maps to var(--fg-3) (subdued foreground token) |
.btn-close (no child <svg>) |
requires child <svg> for × icon |
adds background-image fallback via :has() for bare <button class="btn-close"> |
.btn-close-white |
removed | applies filter: invert(1) grayscale(100%) brightness(200%) |
.form-select |
removed (use .form-control on <select>) |
full styled-select appearance using BS6 form-control tokens |
Bootstrap 5 --bs-* CSS custom properties
Bootstrap 6 dropped the --bs- prefix entirely. Mockup components (pat-contentbrowser, pat-relateditems, etc.) reference the old --bs-* names directly in their Svelte styles. The shim emits a set of --bs-* aliases on :root that resolve to the corresponding Bootstrap 6 tokens:
--bs-* alias |
Resolves to |
|---|---|
--bs-body-bg |
var(--bg-body) |
--bs-border-color |
var(--border-color) |
--bs-border-radius |
var(--radius-3) |
--bs-border-style |
var(--border-style) |
--bs-border-width |
var(--border-width) |
--bs-primary |
var(--primary-base) |
--bs-light |
var(--bg-3) |
--bs-light-bg-subtle |
var(--secondary-bg-subtle) |
--bs-btn-padding-y/x |
var(--btn-input-padding-y/x) |
--bs-btn-font-size |
var(--btn-input-font-size) |
--bs-primary-rgb |
13, 110, 253 (BS5 default; for rgba() expressions) |
--bs-secondary-bg-rgb |
233, 236, 239 (BS5 default; for rgba() expressions) |
[!NOTE] The
--bs-*-rgbvariables are intentionally kept at Bootstrap 5 default values (not the Plone brand color) because they are used exclusively for transparency overlays (rgba(var(--bs-primary-rgb), .25)) in Mockup's compiled Svelte output — overriding them would require recompiling Mockup.
What is not covered
| BS5 feature | Status |
|---|---|
.nav-tabs, .nav-pills, .nav-underline |
unchanged in BS6, no shim needed |
collapse |
still present in BS6 |
Building CSS
See DEVELOPMENT.md for the full development workflow.
Quick build:
cd path/to/plonetheme.bootstrap6
pnpm install
pnpm build
The compiled CSS lands in src/plonetheme/bootstrap6/theme/css/.
Theming & Customisation
The easiest way to customise bootstrap6 is to create a new theme package that depends on it and override individual SCSS partials. Alternatively, use the Diazo TTW editor in Plone's theming control panel to add extra CSS rules on top.
To change a Bootstrap 6 config variable (e.g. primary color), you need to do it via @use "bootstrap/scss/config" with (...) before any other Bootstrap import — follow the pattern in _bs-forward.scss.
Diazo Theme Rules
The Diazo rules are defined in src/plonetheme/bootstrap6/theme/rules.xml and mirror the structure of plonetheme.barceloneta.
Changelog
See CHANGES.md.
Source Code and Contribution
- GitHub: https://github.com/plone/plonetheme.bootstrap6
- Issue tracker: https://github.com/plone/plonetheme.bootstrap6/issues
- Contributing guide: DEVELOPMENT.md
Please read the Plone contributor agreement before submitting a pull request.
License
GNU General Public License v2. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plonetheme_bootstrap6-1.0.0a1.tar.gz.
File metadata
- Download URL: plonetheme_bootstrap6-1.0.0a1.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
626d4a8518a81282d72d7829d5ff7174c87ba63274d2605d4e0f13dab6665de8
|
|
| MD5 |
5d392f372b4b25cfb07fb0d9a08a27c0
|
|
| BLAKE2b-256 |
3a0ae396e2083a09d47171c978535863c34279402d16bbbd8cf0d059a6331342
|
File details
Details for the file plonetheme_bootstrap6-1.0.0a1-py3-none-any.whl.
File metadata
- Download URL: plonetheme_bootstrap6-1.0.0a1-py3-none-any.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b54ef03f5db64921e8da76e74a15c3eace7496f837e02a01459fb76045fe48d5
|
|
| MD5 |
1cd28efd93bc2cff8fb9d9074a052cc0
|
|
| BLAKE2b-256 |
6268dab9e10dd3f4674f850c64bd031842fb8fb9bfe90164e3aa5e246b2aeef0
|