# Bootstrap 5 theme

## INTRODUCTION

This is a very non-prescriptive vanilla Bootstrap 5 theme
with simple configuration. It can be used out of the box or
as a subtheme for creating very flexible web designs with
minimal changes (just override Bootstrap 5 _variables.scss
or this theme's _variables_drupal.scss and recompile css!)

## FEATURES

* Bootstrap 5 library ([5.3.8](https://blog.getbootstrap.com/2025/08/25/bootstrap-5-3-8/)
  and [5.2.3](https://blog.getbootstrap.com/2022/11/22/bootstrap-5-2-3/)) included
* Bootstrap 5 breakpoints
* Bootstrap 5 integration with CKEditor
* Bootstrap 5 configuration within admin user interface
* Interface for creating subtheme
* Can be used as is (subtheme is required for template and CSS overrides)
* Drupal 9 and 10 compatible

## Companion module:

Use [Bootstrap 5 tools](https://www.drupal.org/project/twbstools) companion module for
better content editor and developer experience. Features:

* Bootstrap 5 style guide (view all Bootstrap 5 components on one page)

## REQUIREMENTS

### Installation: composer

INSTALLATION

`composer require drupal/bootstrap5`

Head to `Appearance` and install bootstrap5 theme.

## CONFIGURATION

Head to `Appearance` and clicking bootstrap5 `settings`.

### Subtheme

#### Create a sub-theme using Drush

* `drush --include="web/themes/contrib/bootstrap5/src/Drush" bootstrap5:generate-subtheme MACHINE_NAME --subtheme-name="SUBTHEME_NAME"`

Replace placeholder values before running, e.g.

MACHINE_NAME with my_subtheme
"SUBTHEME_NAME" with "My Subtheme"

* `drush --include="web/themes/contrib/bootstrap5/src/Drush" bootstrap5:generate-subtheme my_subtheme --subtheme-name="My Subtheme"`

#### Create a sub-theme manually

* Enable theme.
* Head to `/admin/appearance/settings/bootstrap5`.
* Scroll down to `Subtheme` section.
* Name your subtheme and click `Create`.

## Development and patching

- Install development dependencies by running `npm install`
- To lint SASS files run `npm run lint:sass` (it will fail build if lint fails)
- To lint JS files run `npm run lint:js` (it will fail build if lint fails)
- To compile SASS run `sass scss/style.scss css/style.css` (requires [SASS compiler](https://sass-lang.com/install))
- To compile SASS for CKEditor5 run `sass scss/ck5style.scss css/ck5style.css`
- To compile JS: run `npm run build:js`
- optional: create symlink from bootstrap5 repo folder to a local Drupal installation to simplify
  development `ln -s /path/to/bootstrap5 /path/to/local-drupal-site/web/themes/contrib`

## Branching

* `4.0.x` Drupal 10/11 support (inclusions: bootstrap icons (included), bootswatch, dark mode, CSS variables)
* `3.0.x` Stable branch based on Starterkit and Stable9 (Drupal 9.4+, Drupal 10+) `deprecated`


## FAQ

### FAQ - CSS returns conflicting results for administrator

If administrator CSS is returning bad results, apply [#3458077 core patch](https://www.drupal.org/project/drupal/issues/3458077).

### FAQ - Adding custom color

* Adding custom color to theme: adding (code snippet)[https://getbootstrap.com/docs/5.3/customize/sass/#add-to-map] to `scss/_variables_bootstrap.scss`.

### FAQ - Menu subnesting

Nesting is considered bad practice in Bootstrap 5. It is bad for UX, mobile
usage and accessibility.

Hence, there are no examples in
the [current documentation](https://getbootstrap.com/docs/5.0/components/dropdowns/#menu-items).

Read more:

* https://github.com/twbs/bootstrap/issues/27659
* https://github.com/twbs/bootstrap/issues/16387#issuecomment-97153831

Theme developers need to implement their own solution if they are catering
for multi level menus.

To get started copy `templates/navigation/menu--main.html.twig` to your
subtheme and modify as follows:

```
{% import _self as menus %}

{#
We call a macro which calls itself to render the full tree.
@see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.build_menu(items, attributes, 0) }}

{% macro build_menu(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
    <ul{{ attributes.addClass('navbar-nav mr-auto') }}>
    {% else %}
    <ul class="dropdown-menu">
    {% endif %}
    {% for item in items %}
      {{ menus.add_link(item, attributes, menu_level) }}
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

{% macro add_link(item, attributes, menu_level) %}
  {% import _self as menus %}
  {%
    set list_item_classes = [
      'nav-item',
      item.is_expanded ? 'dropdown',
      item.is_expanded and (menu_level > 0) ? 'dropdown-submenu',
    ]
  %}
  {%
    set link_class = [
      'nav-item',
      'nav-link',
      item.in_active_trail ? 'active',
      menu_level == 0 and (item.is_expanded or item.is_collapsed) ? 'dropdown-toggle',
    ]
  %}
  {%
    set toggle_class = [
    ]
  %}
  <li{{ item.attributes.addClass(list_item_classes) }}>
    {% if menu_level == 0 %}
      {{ link(item.title, item.url, { 'class': link_class, 'data-toggle' : 'dropdown', 'title': ('Expand menu' | t) ~ ' ' ~ item.title }) }}
    {% else %}
      {{ link(item.title, item.url, { 'class': link_class }) }}
    {% endif %}
    {% if item.below %}
      {{ menus.build_menu(item.below, attributes, menu_level + 1) }}
    {% endif %}
  </li>
{% endmacro %}
```
