This project is not covered by Drupal’s security advisory policy.

Markup keeper is a module that keeps Bootstrap 5 (and other rich) markup — grid, components, data-bs-*
behaviors, utility classes — intact through CKEditor 5 and the "Limit allowed HTML tags" filter, without editing text format configuration. Typically CKEditor5's filters will strip HTML of markup and classes that aren't defined by the CKEditor5 toolbar. The purpose is in case you are writing or generating Bootstrap5 compatible markup from another source vs. writing it directly in the WYSIWYG it will attempt to retain it.

Features

Since Drupal 10's switch to CKEditor 5, pasting Bootstrap-based markup into a 0WYSIWYG field destroys it. Two independent filters cooperate in the destruction: CKEditor 5's Advanced Content Filter strips unknown elements,
classes and attributes on load and save, and the "Limit allowed HTML tags" filter strips them again on render. The usual workarounds are hand-editing each text format's allowed-HTML list (config drift between environments,
silently overwritten by CKEditor 5's own config generation) or dropping the editor entirely ("copy/paste HTML" formats — no WYSIWYG, no safety net).

Markup keeper allows for Bootstrap 5 markup to pass through the HTML filters of both CKEditor 5 and Drupal's core filters.

- Bootstrap 5 layout, component, table and icon elements with any class/id, data-* (incl. data-bs-*) and aria-*; editor + server rules share one source
- Two scope modes:
- Global (default): runtime augmentation, zero stored-config changes
- Per-format: rules stored inside each opted-in format's own allowed HTML,
with a checkbox on the text format edit page; visible in config export,
exact-substring bookkeeping for clean removal across module updates
- Safe by default; form elements are an explicit opt-in on the settings page
- Never unlocks intentionally locked-down formats (empty allowed lists) and never touches configuration imports (isSyncing)
- Hard security line preserved:

, event handlers, javascript: URLs, and inline styles stay blocked — pinned by automated tests - hook_markup_keeper_rules_alter() for site-specific rule tuning - Drupal 10.3, 11 and 12; every core touchpoint statically verified against the 11.x and 12.0.x branches and pinned by 27 Kernel tests (115 assertions) This module doesn't add bootstrap icons or functionality directly to the Ckeditor5 toolbar (see https://drupal.org/project/ckeditor5_bootstrap) for a module that does something like that, but instead allows bootstrap classes and components to bypass the HTML filter that strips them. The point of this module is to allow you to write or generate bootstrap code and then paste the source into Drupal without having it get stripped by Ckeditor5 and without requiring the complete bypass of all filters. In theory bypassing the HTML filter could work for other editors aside from CKEditor5 and in the future we may expand to support other front-end HTML based frameworks such as Tailwind. Known limitations (all documented in the README) - The style attribute cannot pass filter_html at all — core's HTMLPurifier strips it even when a format's own allowed list names it. The module offers no toggle it cannot honor; utility classes are the recommended path. - Bootstrap Icons in tags do not survive CKEditor 5 (core's italic plugin claims ; empty icon holders become empty italic formatting and are dropped). Use Bootstrap's documented pattern — proven round-trip safe. - Markup might be preserved, not rendered: Bootstrap CSS/JS/icon fonts remain the theme's responsibility, and preserved-but-modelless elements may display flattened in the WYSIWYG while being intact in the data (enable CKEditor 5's Source editing for raw-markup inspection). - Security perimeter note: allowed inert markup stays inert unless site or third-party JS re-interprets attribute values (e.g. Bootstrap popovers with data-bs-html=true inject their content as HTML when a theme initializes them). Filter guarantees apply to markup, not to interpreters. This project code was mostly generated via open-weight Qwen 3.8 Flash Next running locally on my own machine as opposed to in the cloud using the Strata engine. I am performing human review and testing to ensure functionality works as intended but at this point it's still a work in progress.

Post-Installation

It adds a config page to Configuration -> Content Editors -> Markup Keeper - /admin/config/content/markup-keeper This is where you can toggle the Global vs. Per text format - by default it applies globally and should work out of the box to allow Bootstrap markup to pass through. But if you plan to have more restricted formats (recommended if you provide a WYSIWYG to the public) then you will need to enable the specific text formats you want this enabled on. In the future we may switch this to the Content Editing per Text Format place. There is also a Allow Bootstrap Form elements checkbox which is probably not recommended to be enabled but might be useful for legacy content.

Additional Requirements

For this to work you still will need to have a Bootstrap 5 library. In addition if you have custom CSS for your HTML you will still need to add it to your theme. This has been tested with the Radix theme. If you want support for Bootstrap Icons you will need to add that library as well, but when added the filter should let them through (although you will likely need to use tags vs. tags as CKEditor5 treats tags as italics. This works with CKEditor5 out of the box and

Similar projects

Typically the way that Bootstrap has been added to CKEditor5 is through the toolbar, there are other modules such as Ckeditor5_bootstrap that do this.

Supporting this Module

This module is brand new and no infrastructure to support it is yet in place.

Community Documentation

There is a README.md file that has the beginnings of this.

Project information

Releases