diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d800c59a40e99fdb1a9225cb414f2b2f9d25bc26..800128593f2b4cb0ad627602d8c1f585c254237b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,3 +7,6 @@ include:
       - '/includes/include.drupalci.main.yml'
       - '/includes/include.drupalci.variables.yml'
       - '/includes/include.drupalci.workflows.yml'
+
+.phpunit-base:
+  allow_failure: true
diff --git a/README.md b/README.md
index f72fc2ca53ab017cef4478ac2826a5f88beafe97..eb0347e5d62ed0725253a2a503f66efdf7aa66c5 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,7 @@ See the [docs](./docs) folder for more detailed documentation on:
 
 This theme requires the following modules:
 - [Layout Options](https://www.drupal.org/project/layout_options)
-- [UI Patterns Library](https://www.drupal.org/project/ui_patterns)
-- [UI Patterns Settings](https://www.drupal.org/project/ui_patterns_settings)
+- [UI Patterns](https://www.drupal.org/project/ui_patterns)
 - [UI Styles](https://www.drupal.org/project/ui_styles)
 
 This theme requires the Bootstrap library to be placed in the `libraries`
diff --git a/assets/css/component/off-canvas.css b/assets/css/component/off-canvas.css
new file mode 100644
index 0000000000000000000000000000000000000000..3db6e4b457c43aa3f6c4d85eef62fd1ad975a1a2
--- /dev/null
+++ b/assets/css/component/off-canvas.css
@@ -0,0 +1,9 @@
+/**
+ * Ensure off-canvas resizing is working.
+ */
+.offcanvas-end {
+  left: auto !important;
+}
+.offcanvas-bottom {
+  top: auto !important;
+}
diff --git a/assets/css/form/off-canvas.button.css b/assets/css/form/off-canvas.button.css
deleted file mode 100644
index 3148d76d67bb80eca69a2bfe31f639fc144e5da5..0000000000000000000000000000000000000000
--- a/assets/css/form/off-canvas.button.css
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Bootstrap 5 use button tag for input to later be able to manage icon.
- *
- * @see core/misc/dialog/off-canvas.button.css
- */
-
-#drupal-off-canvas:not(.drupal-off-canvas-reset) button[type="submit"].button,
-#drupal-off-canvas-wrapper button[type="submit"].button {
-  position: relative;
-  display: inline-block;
-  width: 100%;
-  height: auto;
-  padding: 4px 20px;
-  cursor: pointer;
-  transition: background 0.5s ease;
-  text-align: center;
-  color: #f5f5f5;
-  border: 0;
-  border-radius: 20em;
-  background: #777;
-  font-size: 14px;
-  font-weight: 600;
-}
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button:hover,
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button:focus,
-#drupal-off-canvas:not(.drupal-off-canvas-reset) [type="submit"].button:active,
-#drupal-off-canvas-wrapper button[type="submit"].button:hover,
-#drupal-off-canvas-wrapper button[type="submit"].button:focus,
-#drupal-off-canvas-wrapper [type="submit"].button:active {
-  z-index: 10;
-  text-decoration: none;
-  color: #fff;
-  border: 0;
-  outline: none;
-}
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button:focus,
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button:active,
-#drupal-off-canvas-wrapper button[type="submit"].button:focus,
-#drupal-off-canvas-wrapper button[type="submit"].button:active {
-  box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.1);
-}
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button--primary,
-#drupal-off-canvas-wrapper button[type="submit"].button--primary {
-  margin-top: 15px;
-  color: #fff;
-  border: 0;
-  background: #277abd;
-}
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button--primary:hover,
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button--primary:focus,
-#drupal-off-canvas:not(.drupal-off-canvas-reset)
-  button[type="submit"].button--primary:active,
-#drupal-off-canvas-wrapper button[type="submit"].button--primary:hover,
-#drupal-off-canvas-wrapper button[type="submit"].button--primary:focus,
-#drupal-off-canvas-wrapper button[type="submit"].button--primary:active {
-  outline: none;
-  background: #236aaf;
-}
diff --git a/assets/css/form/off-canvas.form.css b/assets/css/form/off-canvas.form.css
deleted file mode 100644
index 01da91d7680bf155df286e0b351db65eff5adb7c..0000000000000000000000000000000000000000
--- a/assets/css/form/off-canvas.form.css
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Bootstrap 5 places form-text class on description but Drupal places this
- * class on the input.
- *
- * @see core/misc/dialog/off-canvas.form.css
- */
-
-/* Remove form-text input styles applied on description. */
-#drupal-off-canvas:not(.drupal-off-canvas-reset) .description.form-text,
-#drupal-off-canvas-wrapper .description.form-text {
-  max-width: none;
-  padding: 0;
-  border: none;
-  background-color: transparent;
-  box-shadow: none;
-  line-height: normal;
-}
diff --git a/assets/css/media-library/media-library-buttons.css b/assets/css/media-library/media-library-buttons.css
new file mode 100644
index 0000000000000000000000000000000000000000..8dcaed607156dc3856be462851dee3288564b61b
--- /dev/null
+++ b/assets/css/media-library/media-library-buttons.css
@@ -0,0 +1,14 @@
+/* Remove button of selected medias. */
+button[name$="media-library-remove-button"] {
+  position: absolute;
+  z-index: 1;
+  right: var(--bs-card-spacer-x);
+  margin: 0.25rem;
+}
+
+/* Remove button when creating a media. */
+.media-added-remove-button {
+  position: absolute;
+  right: calc(var(--bs-gutter-x) * 0.5 * 3);
+  width: auto;
+}
diff --git a/assets/css/media-library/media-library-container-query.css b/assets/css/media-library/media-library-container-query.css
new file mode 100644
index 0000000000000000000000000000000000000000..157d50423ffc046945bf891401ce949800209d5d
--- /dev/null
+++ b/assets/css/media-library/media-library-container-query.css
@@ -0,0 +1,200 @@
+/**
+ * Custom CSS to handle grid based on the container to be ok normally and in
+ * offcanvas.
+ */
+
+.media-library-widget-wrapper {
+  container-type: inline-size;
+  container-name: media-library-widget-wrapper;
+}
+
+@container media-library-widget-wrapper (min-width: 576px) {
+  .col-cq-sm-1 {
+    width: 8.33333%;
+  }
+  .col-cq-sm-2 {
+    width: 16.66667%;
+  }
+  .col-cq-sm-3 {
+    width: 25%;
+  }
+  .col-cq-sm-4 {
+    width: 33.33333%;
+  }
+  .col-cq-sm-5 {
+    width: 41.66667%;
+  }
+  .col-cq-sm-6 {
+    width: 50%;
+  }
+  .col-cq-sm-7 {
+    width: 58.33333%;
+  }
+  .col-cq-sm-8 {
+    width: 66.66667%;
+  }
+  .col-cq-sm-9 {
+    width: 75%;
+  }
+  .col-cq-sm-10 {
+    width: 83.33333%;
+  }
+  .col-cq-sm-11 {
+    width: 91.66667%;
+  }
+  .col-cq-sm-12 {
+    width: 100%;
+  }
+}
+@container media-library-widget-wrapper (min-width: 768px) {
+  .col-cq-md-1 {
+    width: 8.33333%;
+  }
+  .col-cq-md-2 {
+    width: 16.66667%;
+  }
+  .col-cq-md-3 {
+    width: 25%;
+  }
+  .col-cq-md-4 {
+    width: 33.33333%;
+  }
+  .col-cq-md-5 {
+    width: 41.66667%;
+  }
+  .col-cq-md-6 {
+    width: 50%;
+  }
+  .col-cq-md-7 {
+    width: 58.33333%;
+  }
+  .col-cq-md-8 {
+    width: 66.66667%;
+  }
+  .col-cq-md-9 {
+    width: 75%;
+  }
+  .col-cq-md-10 {
+    width: 83.33333%;
+  }
+  .col-cq-md-11 {
+    width: 91.66667%;
+  }
+  .col-cq-md-12 {
+    width: 100%;
+  }
+}
+@container media-library-widget-wrapper (min-width: 992px) {
+  .col-cq-lg-1 {
+    width: 8.33333%;
+  }
+  .col-cq-lg-2 {
+    width: 16.66667%;
+  }
+  .col-cq-lg-3 {
+    width: 25%;
+  }
+  .col-cq-lg-4 {
+    width: 33.33333%;
+  }
+  .col-cq-lg-5 {
+    width: 41.66667%;
+  }
+  .col-cq-lg-6 {
+    width: 50%;
+  }
+  .col-cq-lg-7 {
+    width: 58.33333%;
+  }
+  .col-cq-lg-8 {
+    width: 66.66667%;
+  }
+  .col-cq-lg-9 {
+    width: 75%;
+  }
+  .col-cq-lg-10 {
+    width: 83.33333%;
+  }
+  .col-cq-lg-11 {
+    width: 91.66667%;
+  }
+  .col-cq-lg-12 {
+    width: 100%;
+  }
+}
+@container media-library-widget-wrapper (min-width: 1200px) {
+  .col-cq-xl-1 {
+    width: 8.33333%;
+  }
+  .col-cq-xl-2 {
+    width: 16.66667%;
+  }
+  .col-cq-xl-3 {
+    width: 25%;
+  }
+  .col-cq-xl-4 {
+    width: 33.33333%;
+  }
+  .col-cq-xl-5 {
+    width: 41.66667%;
+  }
+  .col-cq-xl-6 {
+    width: 50%;
+  }
+  .col-cq-xl-7 {
+    width: 58.33333%;
+  }
+  .col-cq-xl-8 {
+    width: 66.66667%;
+  }
+  .col-cq-xl-9 {
+    width: 75%;
+  }
+  .col-cq-xl-10 {
+    width: 83.33333%;
+  }
+  .col-cq-xl-11 {
+    width: 91.66667%;
+  }
+  .col-cq-xl-12 {
+    width: 100%;
+  }
+}
+@container media-library-widget-wrapper (min-width: 1400px) {
+  .col-cq-xxl-1 {
+    width: 8.33333%;
+  }
+  .col-cq-xxl-2 {
+    width: 16.66667%;
+  }
+  .col-cq-xxl-3 {
+    width: 25%;
+  }
+  .col-cq-xxl-4 {
+    width: 33.33333%;
+  }
+  .col-cq-xxl-5 {
+    width: 41.66667%;
+  }
+  .col-cq-xxl-6 {
+    width: 50%;
+  }
+  .col-cq-xxl-7 {
+    width: 58.33333%;
+  }
+  .col-cq-xxl-8 {
+    width: 66.66667%;
+  }
+  .col-cq-xxl-9 {
+    width: 75%;
+  }
+  .col-cq-xxl-10 {
+    width: 83.33333%;
+  }
+  .col-cq-xxl-11 {
+    width: 91.66667%;
+  }
+  .col-cq-xxl-12 {
+    width: 100%;
+  }
+}
diff --git a/assets/css/media-library/media-library-states.css b/assets/css/media-library/media-library-states.css
new file mode 100644
index 0000000000000000000000000000000000000000..93485f99018fa1de01e0bba05b30593e63a6fd92
--- /dev/null
+++ b/assets/css/media-library/media-library-states.css
@@ -0,0 +1,37 @@
+.media-library-item .card::before {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  content: "";
+  transition:
+    border-color 0.2s,
+    color 0.2s,
+    background 0.2s;
+  pointer-events: none;
+  box-shadow: var(--bs-box-shadow);
+}
+
+.media-library-item.is-hover .card::before,
+.media-library-item.checked .card::before,
+.media-library-item.is-focus .card::before {
+  border: 3px solid;
+  border-radius: var(--bs-card-border-radius);
+}
+
+.media-library-item.is-hover .card::before,
+.media-library-item.checked.is-hover .card::before {
+  border-color: var(--bs-primary);
+}
+
+.media-library-item.is-focus .card::before {
+  border-color: var(--bs-success);
+}
+
+.media-library-item.checked .card::before {
+  border-color: var(--bs-primary-border-subtle);
+}
+
+.media-library-item--disabled {
+  pointer-events: none;
+  opacity: 0.5;
+}
diff --git a/assets/js/misc/dialog/dialog.ajax.js b/assets/js/misc/dialog/dialog.ajax.js
index ec16268d83ed61bba3baf80aef6438d19a78f948..e1605958cd8a0545adb4fed21abc156dc8411c72 100644
--- a/assets/js/misc/dialog/dialog.ajax.js
+++ b/assets/js/misc/dialog/dialog.ajax.js
@@ -28,10 +28,10 @@
           .appendTo('body');
       }
 
-      const $dialog = $context.closest('.modal-content');
+      const $dialog = $context.closest('#drupal-modal');
       if ($dialog.length) {
-        const dialogSettings = $dialog.closest('.modal').data('settings');
-        if (dialogSettings && dialogSettings.drupalAutoButtons) {
+        const drupalAutoButtons = $dialog.data('drupal-auto-buttons');
+        if (drupalAutoButtons) {
           $dialog.trigger('dialogButtonsChange');
         }
       }
@@ -59,7 +59,7 @@
     prepareDialogButtons: function prepareDialogButtons($dialog) {
       const buttons = [];
       const $buttons = $dialog.find(
-        '.form-actions input[type=submit], .form-actions button[type=submit], .form-actions a.button',
+        '.form-actions input[type=submit], .form-actions a.button, .form-actions a.action-link, .form-actions button[type=submit]',
       );
       // eslint-disable-next-line func-names
       $buttons.each(function () {
@@ -102,16 +102,59 @@
     dialogUrlAjax.execute();
   };
 
+  function openOffCanvasDialog(ajax, response, status) {
+    if (!response.selector) {
+      return false;
+    }
+    let $dialog = $(response.selector);
+    if (!$dialog.length) {
+      $dialog = $(
+        `<div id="${response.selector.replace(
+          /^#/,
+          '',
+        )}" class="offcanvas" tabindex="-1" role="dialog"></div>`,
+      ).appendTo('body');
+    }
+
+    // Set up the wrapper, if there isn't one.
+    if (!ajax.wrapper) {
+      ajax.wrapper = $dialog.attr('id');
+    }
+
+    // Use the ajax.js insert command to populate the dialog contents.
+    response.command = 'insert';
+    response.method = 'html';
+    if (
+      response.dialogOptions.modalDialogWrapBody === undefined ||
+      response.dialogOptions.modalDialogWrapBody === true ||
+      response.dialogOptions.modalDialogWrapBody === 'true'
+    ) {
+      response.data = `<div class="offcanvas-body">${response.data}</div>`;
+    }
+    ajax.commands.insert(ajax, response, status);
+
+    // Open the dialog itself.
+    response.dialogOptions = response.dialogOptions || {};
+    const dialog = Drupal.uiSuiteOffCanvas(
+      $dialog.get(0),
+      response.dialogOptions,
+    );
+    if (response.dialogOptions.modal) {
+      dialog.showModal();
+    } else {
+      dialog.show();
+    }
+
+    // Add the standard Drupal class for buttons for style consistency.
+    $dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
+  }
+
   Drupal.AjaxCommands.prototype.coreOpenDialog =
     Drupal.AjaxCommands.prototype.openDialog;
 
   Drupal.AjaxCommands.prototype.openDialog = (ajax, response, status) => {
     if (ajax.dialogRenderer === 'off_canvas') {
-      return Drupal.AjaxCommands.prototype.coreOpenDialog(
-        ajax,
-        response,
-        status,
-      );
+      return openOffCanvasDialog(ajax, response, status);
     }
 
     if (!response.selector) {
@@ -167,6 +210,7 @@
       response.dialogOptions.drupalAutoButtons =
         !!response.dialogOptions.drupalAutoButtons;
     }
+
     if (
       !response.dialogOptions.buttons &&
       response.dialogOptions.drupalAutoButtons
@@ -174,7 +218,10 @@
       response.dialogOptions.buttons =
         Drupal.behaviors.dialog.prepareDialogButtons($dialog);
     }
-
+    $dialog.data(
+      'drupal-auto-buttons',
+      response.dialogOptions.drupalAutoButtons,
+    );
     // Bind dialogButtonsChange.
     $dialog.on('dialogButtonsChange', () => {
       const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
@@ -199,7 +246,11 @@
   Drupal.AjaxCommands.prototype.closeDialog = (ajax, response, status) => {
     const $dialog = $(response.selector);
     if ($dialog.length) {
-      Drupal.uiSuiteDialog($dialog.get(0)).close();
+      if ($dialog.hasClass('offcanvas')) {
+        Drupal.uiSuiteOffCanvas($dialog.get(0)).close();
+      } else {
+        Drupal.uiSuiteDialog($dialog.get(0)).close();
+      }
     }
 
     $dialog.off('dialogButtonsChange');
@@ -214,9 +265,9 @@
   };
 
   // eslint-disable-next-line
-  $(window).on("dialog:aftercreate", (e, dialog, $element, settings) => {
+  $(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
     // eslint-disable-next-line
-    $element.on("click.dialog", ".dialog-cancel", (e) => {
+    $element.on('click.dialog', '.dialog-cancel', (e) => {
       dialog.close('cancel');
       e.preventDefault();
       e.stopPropagation();
diff --git a/assets/js/misc/dialog/dialog.js b/assets/js/misc/dialog/dialog.js
index ca7e6c00d7ea40e11cfb1d379cdb6a33f780c477..6d46bdc1ea2832b7fa0f544dc0ea0496fc6a9dd5 100644
--- a/assets/js/misc/dialog/dialog.js
+++ b/assets/js/misc/dialog/dialog.js
@@ -88,7 +88,14 @@
     }
 
     function updateButtons(buttons) {
-      const modalFooter = $('<div class="modal-footer">');
+      const modalFooter = $(
+        '<div class="modal-footer"><div class="ui-dialog-buttonpane"></div><div class="ui-dialog-buttonset d-flex justify-content-end flex-grow-1"></div>',
+      );
+      const $footer = $('.modal-dialog .modal-content .modal-footer', $element);
+      if ($footer.length > 0) {
+        $($footer).find('.ui-dialog-buttonset').empty();
+      }
+
       // eslint-disable-next-line func-names
       $.each(buttons, function () {
         const buttonObject = this;
@@ -115,15 +122,13 @@
         ) {
           $(button).addClass(classes.join(' '));
         }
-
-        $(modalFooter).append(button);
+        if ($footer.length > 0) {
+          $($footer).find('.ui-dialog-buttonset').append(button);
+        } else {
+          $(modalFooter).find('.ui-dialog-buttonset').append(button);
+        }
       });
-      if (
-        $('.modal-dialog .modal-content .modal-footer', $element).length > 0
-      ) {
-        $('.modal-dialog .modal-content .modal-footer', $element).remove();
-      }
-      if ($(modalFooter).html().length > 0) {
+      if ($(modalFooter).html().length > 0 && $footer.length === 0) {
         $(modalFooter).appendTo($('.modal-dialog .modal-content', $element));
       }
     }
@@ -144,6 +149,14 @@
           .addClass(settings.dialogClasses);
       }
 
+      // For Media library widget.
+      if (
+        settings.classes !== undefined &&
+        settings.classes['ui-dialog'] !== undefined
+      ) {
+        $('.modal-dialog', $element).addClass(settings.classes['ui-dialog']);
+      }
+
       // The modal dialog header.
       if (settingIsTrue(settings.dialogShowHeader)) {
         let modalHeader = '<div class="modal-header">';
@@ -190,11 +203,15 @@
     }
 
     function closeDialog(value) {
+      // eslint-disable-next-line no-undef
+      domElement.dispatchEvent(new DrupalDialogEvent('beforeclose', dialog));
       if ($element.modal !== undefined) {
         $element.modal('hide');
       }
       dialog.returnValue = value;
       dialog.open = false;
+      // eslint-disable-next-line no-undef
+      domElement.dispatchEvent(new DrupalDialogEvent('afterclose', dialog));
     }
 
     dialog.updateButtons = (buttons) => {
diff --git a/assets/js/misc/dialog/dialog.off-canvas.js b/assets/js/misc/dialog/dialog.off-canvas.js
new file mode 100644
index 0000000000000000000000000000000000000000..732f29a33076faca906391a4c300f681c13e63d6
--- /dev/null
+++ b/assets/js/misc/dialog/dialog.off-canvas.js
@@ -0,0 +1,205 @@
+/**
+ * @file
+ * Dialog API inspired by HTML5 dialog element.
+ *
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
+ */
+
+(($, Drupal, drupalSettings) => {
+  /**
+   * Default dialog options.
+   *
+   * @type {object}
+   *
+   * @prop {bool} [autoOpen=true]
+   * @prop {bool} [autoResize=undefined]
+   * @prop {bool} [backdrop=undefined]
+   * @prop {object} [classes=undefined] TODO
+   * @prop {function} close
+   * @prop {string} [dialogClasses='']
+   * @prop {string} [dialogHeadingLevel=5]
+   * @prop {string} [dialogShowHeader=true]
+   * @prop {string} [dialogShowHeaderTitle=true]
+   * @prop {string} [dialogStatic=false]
+   * @prop {bool} [drupalAutoButtons=undefined]
+   * @prop {bool} [drupalOffCanvasPosition='side']
+   * @prop {bool} [resizable=undefined]
+   * @prop {string} [title=undefined]
+   * @prop {string} [width=undefined]
+   */
+  drupalSettings.offCanvas = {
+    autoOpen: true,
+    autoResize: undefined,
+    backdrop: undefined,
+    classes: undefined,
+    close: function close(event) {
+      Drupal.uiSuiteDialog(event.target).close();
+      Drupal.detachBehaviors(event.target, null, 'unload');
+    },
+    dialogHeadingLevel: 5,
+    dialogShowHeader: true,
+    dialogShowHeaderTitle: true,
+    dialogStatic: false,
+    drupalAutoButtons: undefined,
+    drupalOffCanvasPosition: 'side',
+    resizable: undefined,
+    title: undefined,
+    width: undefined,
+  };
+
+  /**
+   * @typedef {object} Drupal.dialog~dialogDefinition
+   *
+   * @prop {boolean} open
+   *   Is the dialog open or not.
+   * @prop {*} returnValue
+   *   Return value of the dialog.
+   * @prop {function} show
+   *   Method to display the dialog on the page.
+   * @prop {function} showModal
+   *   Method to display the dialog as a modal on the page.
+   * @prop {function} close
+   *   Method to hide the dialog from the page.
+   */
+
+  /**
+   * Polyfill HTML5 dialog element with jQueryUI.
+   *
+   * @param {HTMLElement} element
+   *   The element that holds the dialog.
+   * @param {object} options
+   *   jQuery UI options to be passed to the dialog.
+   *
+   * @return {Drupal.dialog~dialogDefinition}
+   *   The dialog instance.
+   */
+  Drupal.uiSuiteOffCanvas = (element, options) => {
+    let undef;
+
+    const $element = $(element);
+    const domElement = $element.get(0);
+
+    const dialog = {
+      open: false,
+      returnValue: undef,
+    };
+
+    options = $.extend({}, drupalSettings.offCanvas, options);
+
+    function settingIsTrue(setting) {
+      return setting !== undefined && (setting === true || setting === 'true');
+    }
+
+    function openDialog(settings) {
+      settings = $.extend({}, options, settings);
+
+      // eslint-disable-next-line no-undef
+      const event = new DrupalDialogEvent('beforecreate', dialog, settings);
+      domElement.dispatchEvent(event);
+      dialog.open = true;
+      settings = event.settings;
+
+      // Position
+      if (settings.drupalOffCanvasPosition === 'side') {
+        $element.addClass('offcanvas-end');
+      } else if (settings.drupalOffCanvasPosition === 'top') {
+        $element.addClass('offcanvas-top');
+      } else if (settings.drupalOffCanvasPosition === 'bottom') {
+        $element.addClass('offcanvas-bottom');
+      }
+
+      // Classes
+      if (settings.classes) {
+        if (settings.classes['ui-dialog']) {
+          $element.addClass(settings.classes['ui-dialog']);
+        }
+        if (settings.classes['ui-dialog-content']) {
+          $('.offcanvas-body', $element).addClass(
+            settings.classes['ui-dialog-content'],
+          );
+        }
+      }
+
+      // The offcanvas dialog header.
+      if (settingIsTrue(settings.dialogShowHeader)) {
+        let offCanvasHeader = '<div class="offcanvas-header">';
+        const heading = settings.dialogHeadingLevel;
+
+        if (settingIsTrue(settings.dialogShowHeaderTitle)) {
+          offCanvasHeader += `<h${heading} class="offcanvas-title" id="offcanvasLabel">${settings.title}</h${heading}>`;
+        }
+
+        offCanvasHeader += `<button type="button" class="close btn-close" data-bs-dismiss="offcanvas" aria-label="${Drupal.t(
+          'Close',
+        )}"></button></div>`;
+
+        $(offCanvasHeader).prependTo($element);
+      }
+
+      if (settingIsTrue(settings.dialogStatic)) {
+        $element.attr('data-bs-backdrop', 'static');
+      }
+
+      if (!settingIsTrue(settings.backdrop)) {
+        $element.attr('data-bs-scroll', 'true');
+      }
+
+      if ($element.offcanvas !== undefined) {
+        $element.offcanvas(settings);
+        $element.offcanvas('show');
+      }
+
+      if (settings.width) {
+        $element[0].style.setProperty(
+          '--bs-offcanvas-width',
+          typeof settings.width === 'number'
+            ? `${settings.width}px`
+            : settings.width,
+        );
+      }
+
+      if ($element.resizable !== undefined && settings.resizable) {
+        $element.resizable({
+          handles: 'w',
+        });
+      }
+
+      domElement.dispatchEvent(
+        // eslint-disable-next-line no-undef
+        new DrupalDialogEvent('aftercreate', dialog, settings),
+      );
+    }
+
+    function closeDialog(value) {
+      if ($element.modal !== undefined) {
+        $element.offcanvas('hide');
+      }
+      dialog.returnValue = value;
+      dialog.open = false;
+    }
+
+    dialog.show = () => {
+      openDialog({ backdrop: false });
+    };
+    dialog.showModal = () => {
+      openDialog({ backdrop: true });
+    };
+    dialog.close = () => {
+      closeDialog({});
+    };
+
+    $element.on('hide.bs.offcanvas', () => {
+      // eslint-disable-next-line no-undef
+      domElement.dispatchEvent(new DrupalDialogEvent('beforeclose', dialog));
+    });
+
+    $element.on('hidden.bs.offcanvas', () => {
+      // eslint-disable-next-line no-undef
+      domElement.dispatchEvent(new DrupalDialogEvent('afterclose', dialog));
+    });
+
+    return dialog;
+  };
+
+  Drupal.behaviors.offCanvasEvents = {};
+})(jQuery, Drupal, drupalSettings);
diff --git a/components/accordion/accordion.component.yml b/components/accordion/accordion.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3597c1d96bae46df77aaba6d3eb434e17e7f1d8f
--- /dev/null
+++ b/components/accordion/accordion.component.yml
@@ -0,0 +1,32 @@
+name: Accordion
+description: "Render content in a box that expands and collapses vertically."
+group: Accordion
+links:
+  - "https://getbootstrap.com/docs/5.3/components/accordion/"
+variants:
+  default:
+    title: Default
+  flush:
+    title: Flush
+    description: "Remove the default background color, some borders, and some rounded corners to render accordions edge-to-edge with their parent container."
+slots:
+  content:
+    title: Content
+    description: "Accordion items."
+props:
+  type: object
+  properties:
+    keep_open:
+      title: "Keep open?"
+      description: "Make accordion items stay open when another item is opened."
+      type: boolean
+    accordion_id:
+      title: ID
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+libraryOverrides:
+  js:
+    js/accordion.js: {}
+  dependencies:
+    - core/drupal
+    - core/once
diff --git a/components/accordion/accordion.preview.story.yml b/components/accordion/accordion.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0657e81b46fbe06e0a2a800d3a4e5b6f776bcafc
--- /dev/null
+++ b/components/accordion/accordion.preview.story.yml
@@ -0,0 +1,45 @@
+name: Preview
+slots:
+  content:
+    - type: component
+      component: "ui_suite_bootstrap:accordion_item"
+      slots:
+        title: "Accordion Item #1"
+        content:
+          type: html_tag
+          tag: p
+          value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
+      props:
+        opened: true
+    - type: component
+      component: "ui_suite_bootstrap:accordion_item"
+      slots:
+        title: "Accordion Item #2"
+        content:
+          type: html_tag
+          tag: p
+          value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
+      props:
+        opened: false
+    - type: component
+      component: "ui_suite_bootstrap:accordion_item"
+      slots:
+        title: "Accordion Item #3"
+        content:
+          type: html_tag
+          tag: p
+          value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
+      props:
+        opened: false
+    - type: component
+      component: "ui_suite_bootstrap:accordion_item"
+      slots:
+        title: "Accordion Item #4"
+        content:
+          type: html_tag
+          tag: p
+          value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
+      props:
+        opened: false
+props:
+  keep_open: false
diff --git a/templates/patterns/accordion/pattern-accordion.html.twig b/components/accordion/accordion.twig
similarity index 100%
rename from templates/patterns/accordion/pattern-accordion.html.twig
rename to components/accordion/accordion.twig
diff --git a/templates/patterns/accordion/js/accordion.js b/components/accordion/js/accordion.js
similarity index 100%
rename from templates/patterns/accordion/js/accordion.js
rename to components/accordion/js/accordion.js
diff --git a/components/accordion_item/accordion_item.component.yml b/components/accordion_item/accordion_item.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..70aa37d28b1fb0475778decb3db018e25e74fb2b
--- /dev/null
+++ b/components/accordion_item/accordion_item.component.yml
@@ -0,0 +1,38 @@
+name: "(Accordion item)"
+description: "Internal: to be used in the 'Accordion' component."
+group: Accordion
+links:
+  - "https://getbootstrap.com/docs/5.3/components/accordion"
+slots:
+  title:
+    title: Title
+    description: "Item title."
+  content:
+    title: Content
+    description: "Accordion item content."
+props:
+  type: object
+  properties:
+    opened:
+      title: Opened
+      description: "If the accordion item is opened by default."
+      type: boolean
+    heading_level:
+      title: "Heading level"
+      type: integer
+      enum:
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        2: "h2 (Default)"
+        3: h3
+        4: h4
+        5: h5
+        6: h6
+    item_id:
+      title: ID
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
diff --git a/templates/patterns/accordion_item/pattern-accordion-item.html.twig b/components/accordion_item/accordion_item.twig
similarity index 89%
rename from templates/patterns/accordion_item/pattern-accordion-item.html.twig
rename to components/accordion_item/accordion_item.twig
index 41fa78a9e1a42ae2e0a73c0b45409d6cf90987aa..479ffaa529b036a18c193ac876a795477b6572db 100644
--- a/templates/patterns/accordion_item/pattern-accordion-item.html.twig
+++ b/components/accordion_item/accordion_item.twig
@@ -5,13 +5,13 @@
 set button_attributes = create_attribute({
   'class': [
     'accordion-button',
-    'collapsed'
+    'collapsed',
   ],
   'type': 'button',
   'data-bs-toggle': 'collapse',
   'data-bs-target': '#' ~ item_id,
   'aria-controls': item_id,
-  'aria-expanded': 'false'
+  'aria-expanded': 'false',
 })
 %}
 
@@ -21,9 +21,9 @@ set content_attributes = create_attribute({
   'class': [
     'accordion-collapse',
     'collapse',
-    'js-accordion-keep-open'
+    'js-accordion-keep-open',
   ],
-  'aria-labelledby': 'heading--' ~ item_id
+  'aria-labelledby': 'heading--' ~ item_id,
 })
 %}
 
diff --git a/components/alert/alert.component.yml b/components/alert/alert.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..178862d4f4b5441e4e57e5b39501a193753f52e9
--- /dev/null
+++ b/components/alert/alert.component.yml
@@ -0,0 +1,39 @@
+name: Alert
+description: "Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages."
+links:
+  - "https://getbootstrap.com/docs/5.3/components/alerts/"
+variants:
+  primary:
+    title: Primary
+  secondary:
+    title: Secondary
+  success:
+    title: Success
+  danger:
+    title: Danger
+  warning:
+    title: Warning
+  info:
+    title: Info
+  light:
+    title: Light
+  dark:
+    title: Dark
+slots:
+  heading:
+    title: Heading
+    description: "The alert heading. Optional."
+  message:
+    title: Message
+    description: "The alert message."
+props:
+  type: object
+  properties:
+    dismissible:
+      title: "Dismissible?"
+      description: "It is possible to dismiss any alert inline."
+      type: boolean
+libraryOverrides:
+  css:
+    component:
+      styles/alert.css: {}
diff --git a/components/alert/alert.preview.story.yml b/components/alert/alert.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..337b26580f5aafefab0592f70616c6290d56a075
--- /dev/null
+++ b/components/alert/alert.preview.story.yml
@@ -0,0 +1,6 @@
+name: Preview
+slots:
+  heading: "Well done!"
+  message: "A simple alert. Check it out!"
+props:
+  dismissible: true
diff --git a/templates/patterns/alert/pattern-alert.html.twig b/components/alert/alert.twig
similarity index 77%
rename from templates/patterns/alert/pattern-alert.html.twig
rename to components/alert/alert.twig
index 971d1d71bcfde57ba0578b977a6b5705a97b8055..236e8cd6d376c2d8589d8662009a4423695209b8 100644
--- a/templates/patterns/alert/pattern-alert.html.twig
+++ b/components/alert/alert.twig
@@ -12,11 +12,11 @@
   {% endif %}
   {{ message }}
   {% if dismissible %}
-    {{ pattern('close_button', {
-      attributes: create_attribute({
-        'data-bs-dismiss': 'alert'
-      }),
+    {{ include('ui_suite_bootstrap:close_button', {
+      attributes: {
+        'data-bs-dismiss': 'alert',
+      },
       aria_label: 'Close'|t,
-    }) }}
+    }, with_context = false) }}
   {% endif %}
 </div>
diff --git a/templates/patterns/alert/styles/alert.css b/components/alert/styles/alert.css
similarity index 100%
rename from templates/patterns/alert/styles/alert.css
rename to components/alert/styles/alert.css
diff --git a/components/badge/badge.component.yml b/components/badge/badge.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a2aae676f509b96058a5ba32c78ef90dcd2cc8cf
--- /dev/null
+++ b/components/badge/badge.component.yml
@@ -0,0 +1,8 @@
+name: Badge
+description: "A small count and labeling component. Badges scale to match the size of the immediate parent element by using relative font sizing and em units."
+links:
+  - "https://getbootstrap.com/docs/5.3/components/badge/"
+slots:
+  label:
+    title: Label
+    description: "The badge's label."
diff --git a/components/badge/badge.preview.story.yml b/components/badge/badge.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..df97b4bde773e0f5e6dda38660477f60df5d1fff
--- /dev/null
+++ b/components/badge/badge.preview.story.yml
@@ -0,0 +1,7 @@
+name: Preview
+slots:
+  label: New
+props:
+  attributes:
+    class:
+      - text-bg-primary
diff --git a/templates/patterns/badge/pattern-badge.html.twig b/components/badge/badge.twig
similarity index 100%
rename from templates/patterns/badge/pattern-badge.html.twig
rename to components/badge/badge.twig
diff --git a/components/blockquote/blockquote.component.yml b/components/blockquote/blockquote.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9b3f868378d8c1dc8567daa3b7604c5887ea58f1
--- /dev/null
+++ b/components/blockquote/blockquote.component.yml
@@ -0,0 +1,12 @@
+name: Blockquote
+description: "For quoting blocks of content from another source within your document."
+group: Typography
+links:
+  - "https://getbootstrap.com/docs/5.3/content/typography/#blockquotes"
+slots:
+  content:
+    title: Content
+    description: "The quote."
+  footer:
+    title: Footer
+    description: "For identifying the source. Wrap the name of the source work in <cite>."
diff --git a/components/blockquote/blockquote.preview.story.yml b/components/blockquote/blockquote.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7620fe5674b755ca6df9796c25b1f9d204ac9027
--- /dev/null
+++ b/components/blockquote/blockquote.preview.story.yml
@@ -0,0 +1,13 @@
+name: Preview
+slots:
+  content:
+    - type: html_tag
+      tag: p
+      value: "A well-known quote, contained in a blockquote element."
+  footer:
+    - markup: "Someone famous in "
+    - type: html_tag
+      tag: cite
+      value: "Source Title"
+      attributes:
+        title: "Source Title"
diff --git a/templates/patterns/blockquote/pattern-blockquote.html.twig b/components/blockquote/blockquote.twig
similarity index 100%
rename from templates/patterns/blockquote/pattern-blockquote.html.twig
rename to components/blockquote/blockquote.twig
diff --git a/components/breadcrumb/breadcrumb.component.yml b/components/breadcrumb/breadcrumb.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..feb569f98a76cfa7bdc281e81f5cfc66146b427d
--- /dev/null
+++ b/components/breadcrumb/breadcrumb.component.yml
@@ -0,0 +1,11 @@
+name: Breadcrumb
+description: "Indicate the current page’s location within a navigational hierarchy that automatically adds separators via CSS."
+group: Navigation
+links:
+  - "https://getbootstrap.com/docs/5.3/components/breadcrumb/"
+props:
+  type: object
+  properties:
+    items:
+      title: Items
+      $ref: "ui-patterns://links"
diff --git a/components/breadcrumb/breadcrumb.preview.story.yml b/components/breadcrumb/breadcrumb.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..070173ed189a6fdc2ae0a9ba6fbe8e2f255ed5ff
--- /dev/null
+++ b/components/breadcrumb/breadcrumb.preview.story.yml
@@ -0,0 +1,8 @@
+name: Preview
+props:
+  items:
+    - title: Home
+      url: "#"
+    - title: Library
+      url: "#"
+    - title: Data
diff --git a/templates/patterns/breadcrumb/pattern-breadcrumb.html.twig b/components/breadcrumb/breadcrumb.twig
similarity index 100%
rename from templates/patterns/breadcrumb/pattern-breadcrumb.html.twig
rename to components/breadcrumb/breadcrumb.twig
diff --git a/components/button/button.component.yml b/components/button/button.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..18e12d9dbb9b8a9f7a5f58e5455cff4619645de4
--- /dev/null
+++ b/components/button/button.component.yml
@@ -0,0 +1,130 @@
+name: Button
+description: "For actions in forms, dialogs, and more with support for multiple sizes, states, and more."
+group: Button
+links:
+  - "https://getbootstrap.com/docs/5.3/components/buttons/"
+variants:
+  default:
+    title: Default
+    description: "No 'btn' class added."
+  primary__sm:
+    title: "Primary small"
+  secondary__sm:
+    title: "Secondary small"
+  success__sm:
+    title: "Success small"
+  danger__sm:
+    title: "Danger small"
+  warning__sm:
+    title: "Warning small"
+  info__sm:
+    title: "Info small"
+  light__sm:
+    title: "Light small"
+  dark__sm:
+    title: "Dark small"
+  link__sm:
+    title: "Link small"
+  primary:
+    title: Primary
+  secondary:
+    title: Secondary
+  success:
+    title: Success
+  danger:
+    title: Danger
+  warning:
+    title: Warning
+  info:
+    title: Info
+  light:
+    title: Light
+  dark:
+    title: Dark
+  link:
+    title: Link
+  primary__lg:
+    title: "Primary large"
+  secondary__lg:
+    title: "Secondary large"
+  success__lg:
+    title: "Success large"
+  danger__lg:
+    title: "Danger large"
+  warning__lg:
+    title: "Warning large"
+  info__lg:
+    title: "Info large"
+  light__lg:
+    title: "Light large"
+  dark__lg:
+    title: "Dark large"
+  link__lg:
+    title: "Link large"
+  outline_primary__sm:
+    title: "Outline Primary small"
+  outline_secondary__sm:
+    title: "Outline Secondary small"
+  outline_success__sm:
+    title: "Outline Success small"
+  outline_danger__sm:
+    title: "Outline Danger small"
+  outline_warning__sm:
+    title: "Outline Warning small"
+  outline_info__sm:
+    title: "Outline Info small"
+  outline_light__sm:
+    title: "Outline Light small"
+  outline_dark__sm:
+    title: "Outline Dark small"
+  outline_primary:
+    title: "Outline Primary"
+  outline_secondary:
+    title: "Outline Secondary"
+  outline_success:
+    title: "Outline Success"
+  outline_danger:
+    title: "Outline Danger"
+  outline_warning:
+    title: "Outline Warning"
+  outline_info:
+    title: "Outline Info"
+  outline_light:
+    title: "Outline Light"
+  outline_dark:
+    title: "Outline Dark"
+  outline_primary__lg:
+    title: "Outline Primary large"
+  outline_secondary__lg:
+    title: "Outline Secondary large"
+  outline_success__lg:
+    title: "Outline Success large"
+  outline_danger__lg:
+    title: "Outline Danger large"
+  outline_warning__lg:
+    title: "Outline Warning large"
+  outline_info__lg:
+    title: "Outline Info large"
+  outline_light__lg:
+    title: "Outline Light large"
+  outline_dark__lg:
+    title: "Outline Dark large"
+slots:
+  label:
+    title: Label
+    description: "The button label."
+props:
+  type: object
+  properties:
+    disabled:
+      title: "Disabled?"
+      description: "Is the button disabled?"
+      type: boolean
+    label_visually_hidden:
+      title: "Hide button label?"
+      description: "Is the button's label hidden?"
+      type: boolean
+    url:
+      title: URL
+      description: "The button URL. Optional."
+      $ref: "ui-patterns://url"
diff --git a/components/button/button.preview.story.yml b/components/button/button.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4cc11dda5f11adcc5259d587ef1d9b38df1880fb
--- /dev/null
+++ b/components/button/button.preview.story.yml
@@ -0,0 +1,7 @@
+name: Preview
+slots:
+  label: Submit
+props:
+  disabled: false
+  label_visually_hidden: false
+  url: "https://example.com"
diff --git a/templates/patterns/button/pattern-button.html.twig b/components/button/button.twig
similarity index 100%
rename from templates/patterns/button/pattern-button.html.twig
rename to components/button/button.twig
diff --git a/components/button_group/button_group.component.yml b/components/button_group/button_group.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..80f1afef512f79c7245bdc2641fd020258981835
--- /dev/null
+++ b/components/button_group/button_group.component.yml
@@ -0,0 +1,26 @@
+name: "Button Group"
+description: "Group a series of buttons together on a single line with the button group, and super-power them with JavaScript."
+group: Button
+links:
+  - "https://getbootstrap.com/docs/5.3/components/button-group/"
+variants:
+  sm:
+    title: Small
+  default:
+    title: Default
+  lg:
+    title: Large
+  vertical:
+    title: Vertical
+    description: "Make a set of buttons appear vertically stacked rather than horizontally. Split button dropdowns are not supported here."
+slots:
+  buttons:
+    title: Buttons
+    description: "An array of 'button' patterns."
+props:
+  type: object
+  properties:
+    label:
+      title: Role
+      description: "The group label. Visually hidden. Used with assistive technologies."
+      type: string
diff --git a/components/button_group/button_group.preview.story.yml b/components/button_group/button_group.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1574045d2d97a05ddbdfe1a6a5443db865f5085a
--- /dev/null
+++ b/components/button_group/button_group.preview.story.yml
@@ -0,0 +1,23 @@
+name: Preview
+slots:
+  buttons:
+    - type: component
+      component: "ui_suite_bootstrap:button"
+      slots:
+        label: First
+      props:
+        variant: secondary
+    - type: component
+      component: "ui_suite_bootstrap:button"
+      slots:
+        label: Second
+      props:
+        variant: secondary
+    - type: component
+      component: "ui_suite_bootstrap:button"
+      slots:
+        label: Third
+      props:
+        variant: secondary
+props:
+  label: "Basic example"
diff --git a/templates/patterns/button_group/pattern-button-group.html.twig b/components/button_group/button_group.twig
similarity index 100%
rename from templates/patterns/button_group/pattern-button-group.html.twig
rename to components/button_group/button_group.twig
diff --git a/components/button_toolbar/button_toolbar.component.yml b/components/button_toolbar/button_toolbar.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d9cef1a4c40fb753693d29dc760c8e79e0e69141
--- /dev/null
+++ b/components/button_toolbar/button_toolbar.component.yml
@@ -0,0 +1,16 @@
+name: "Button Toolbar"
+description: "Combine sets of button groups into button toolbars for more complex components. Use utility classes as needed to space out groups, buttons, and more."
+group: Button
+links:
+  - "https://getbootstrap.com/docs/5.3/components/button-group/#button-toolbar"
+slots:
+  groups:
+    title: Groups
+    description: "An array of 'button_group' patterns. Or other 'groupable' elements."
+props:
+  type: object
+  properties:
+    label:
+      title: Role
+      description: "The toolbar label. Visually hidden. Used with assistive technologies."
+      type: string
diff --git a/components/button_toolbar/button_toolbar.preview.story.yml b/components/button_toolbar/button_toolbar.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ab046ccbf8094174b0517e49001eb0077686f7e0
--- /dev/null
+++ b/components/button_toolbar/button_toolbar.preview.story.yml
@@ -0,0 +1,26 @@
+name: Preview
+slots:
+  groups:
+    - type: component
+      attributes:
+        class:
+          - me-2
+      component: "ui_suite_bootstrap:button_group"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      attributes:
+        class:
+          - me-2
+      component: "ui_suite_bootstrap:button_group"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:button_group"
+      story: preview
+      props:
+        variant: default
+props:
+  label: "Toolbar with button groups"
diff --git a/templates/patterns/button_toolbar/pattern-button-toolbar.html.twig b/components/button_toolbar/button_toolbar.twig
similarity index 100%
rename from templates/patterns/button_toolbar/pattern-button-toolbar.html.twig
rename to components/button_toolbar/button_toolbar.twig
diff --git a/components/card/card.component.yml b/components/card/card.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bedf5ded1e629988bc0221cb85e6068bd5fb60b8
--- /dev/null
+++ b/components/card/card.component.yml
@@ -0,0 +1,46 @@
+name: Card
+description: "A card is a flexible and extensible content container. It includes options for headers and footers, a wide variety of content, contextual background colors, and powerful display options."
+group: Card
+links:
+  - "https://getbootstrap.com/docs/5.3/components/card/"
+variants:
+  default:
+    title: Default
+  horizontal:
+    title: Horizontal
+slots:
+  image:
+    title: Image
+    description: "Card image."
+  header:
+    title: Header
+    description: "Card header."
+  content:
+    title: Content
+    description: "Card body."
+  footer:
+    title: Footer
+    description: "Card footer."
+props:
+  type: object
+  properties:
+    image_position:
+      title: "Image position"
+      description: "Only for default variant."
+      type: string
+      enum:
+        - top
+        - bottom
+      "meta:enum":
+        top: "Top (Default)"
+        bottom: Bottom
+    image_col_classes:
+      title: "Image column classes"
+      description: "Only for horizontal variant. Default value: col-md-4"
+      type: string
+      default: col-md-4
+    content_col_classes:
+      title: "Content column classes"
+      description: "Only for horizontal variant. Default value: col-md-8"
+      type: string
+      default: col-md-8
diff --git a/components/card/card.horizontal.story.yml b/components/card/card.horizontal.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..54886930bf262fef440600189347653e5dac8059
--- /dev/null
+++ b/components/card/card.horizontal.story.yml
@@ -0,0 +1,37 @@
+name: Horizontal
+slots:
+  image:
+    theme: image
+    uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
+    alt: "&copy; 2017 John Smith photography"
+  content:
+    - type: component
+      component: "ui_suite_bootstrap:card_body"
+      slots:
+        title: "Card title"
+        subtitle: "Card subtitle"
+        text: "Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit."
+        content:
+          type: component
+          component: "ui_suite_bootstrap:button"
+          slots:
+            label: "Go somewhere"
+          props:
+            variant: primary
+        links:
+          - type: html_tag
+            tag: a
+            value: "Card link"
+            attributes:
+              href: "#"
+          - type: html_tag
+            tag: a
+            value: "Another link"
+            attributes:
+              href: "#"
+props:
+  attributes:
+    style: "max-width: 540px;"
+  variant: horizontal
+  image_col_classes: col-md-4
+  content_col_classes: col-md-8
diff --git a/components/card/card.preview.story.yml b/components/card/card.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e27538aae524f79866ef478b0ec7847c62f5e3ed
--- /dev/null
+++ b/components/card/card.preview.story.yml
@@ -0,0 +1,39 @@
+name: Preview
+slots:
+  image:
+    theme: image
+    uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
+    alt: "&copy; 2017 John Smith photography"
+  header: Featured
+  content:
+    - type: component
+      component: "ui_suite_bootstrap:card_body"
+      slots:
+        title: "Card title"
+        subtitle: "Card subtitle"
+        text: "Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit."
+        content:
+          type: component
+          component: "ui_suite_bootstrap:button"
+          slots:
+            label: "Go somewhere"
+          props:
+            variant: primary
+        links:
+          - type: html_tag
+            tag: a
+            value: "Card link"
+            attributes:
+              href: "#"
+          - type: html_tag
+            tag: a
+            value: "Another link"
+            attributes:
+              href: "#"
+  footer:
+    type: html_tag
+    tag: span
+    value: "2 days ago"
+props:
+  variant: default
+  image_position: top
diff --git a/templates/patterns/card/pattern-card.html.twig b/components/card/card.twig
similarity index 100%
rename from templates/patterns/card/pattern-card.html.twig
rename to components/card/card.twig
diff --git a/components/card_body/card_body.component.yml b/components/card_body/card_body.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ad3409d224dac1f1e5fd4de574c3d30f053f761e
--- /dev/null
+++ b/components/card_body/card_body.component.yml
@@ -0,0 +1,39 @@
+name: "(Card body)"
+description: "Internal: to be used in the 'Card' component, because a card can have multiple 'Card body' components."
+group: Card
+links:
+  - "https://getbootstrap.com/docs/5.3/components/card/"
+slots:
+  title:
+    title: Title
+    description: "Card title. Plain text."
+  subtitle:
+    title: Subtitle
+    description: "Card subtitle. Plain text."
+  text:
+    title: Text
+    description: "Card text. Plain text."
+  content:
+    title: Content
+    description: "Free content outside of any wrapper."
+  links:
+    title: Links
+    description: "Array of link elements"
+props:
+  type: object
+  properties:
+    heading_level:
+      title: "Heading level"
+      type: integer
+      enum:
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        2: h2
+        3: h3
+        4: h4
+        5: "h5 (Default)"
+        6: h6
diff --git a/templates/patterns/card_body/pattern-card-body.html.twig b/components/card_body/card_body.twig
similarity index 100%
rename from templates/patterns/card_body/pattern-card-body.html.twig
rename to components/card_body/card_body.twig
diff --git a/components/card_group/card_group.component.yml b/components/card_group/card_group.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a2a247b41cb341ec597baa97e1fc9a81f5ac120a
--- /dev/null
+++ b/components/card_group/card_group.component.yml
@@ -0,0 +1,9 @@
+name: "Card group"
+description: "Use card groups to render cards as a single, attached element with equal width and height columns. Card groups start off stacked and use display: flex; to become attached with uniform dimensions starting at the sm breakpoint. When using card groups with footers, their content will automatically line up."
+group: Card
+links:
+  - "https://getbootstrap.com/docs/5.3/components/card/#card-groups"
+slots:
+  cards:
+    title: Cards
+    description: "An array of card patterns."
diff --git a/components/card_group/card_group.preview.story.yml b/components/card_group/card_group.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..31ba81bca678b4b2d6a2bce1ff42bc24640eeede
--- /dev/null
+++ b/components/card_group/card_group.preview.story.yml
@@ -0,0 +1,18 @@
+name: Preview
+slots:
+  cards:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
diff --git a/templates/patterns/card_group/pattern-card-group.html.twig b/components/card_group/card_group.twig
similarity index 100%
rename from templates/patterns/card_group/pattern-card-group.html.twig
rename to components/card_group/card_group.twig
diff --git a/components/card_overlay/card_overlay.component.yml b/components/card_overlay/card_overlay.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2850b8bc7b5dc954d7d372e60b4f2f36ab601148
--- /dev/null
+++ b/components/card_overlay/card_overlay.component.yml
@@ -0,0 +1,42 @@
+name: "Card overlay"
+description: "Turn an image into a card background and overlay your card’s text. Depending on the image, you may or may not need additional styles or utilities."
+group: Card
+links:
+  - "https://getbootstrap.com/docs/5.3/components/card/#image-overlays"
+slots:
+  image:
+    title: Image
+    description: "Card image."
+  title:
+    title: Title
+    description: "Card title. Plain text."
+  subtitle:
+    title: Subtitle
+    description: "Card subtitle. Plain text."
+  text:
+    title: Text
+    description: "Card text. Plain text."
+  content:
+    title: Content
+    description: "Free content outside of any wrapper."
+  links:
+    title: Links
+    description: "Array of link elements"
+props:
+  type: object
+  properties:
+    heading_level:
+      title: "Heading level"
+      type: integer
+      enum:
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        2: h2
+        3: h3
+        4: h4
+        5: "h5 (Default)"
+        6: h6
diff --git a/components/card_overlay/card_overlay.preview.story.yml b/components/card_overlay/card_overlay.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..77e917da4be663cafd2ae51444e39a53e7d1e833
--- /dev/null
+++ b/components/card_overlay/card_overlay.preview.story.yml
@@ -0,0 +1,32 @@
+name: Preview
+slots:
+  image:
+    theme: image
+    uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
+    alt: "&copy; 2017 John Smith photography"
+  title: "Card title"
+  subtitle: "Card subtitle"
+  text: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer."
+  content:
+    type: html_tag
+    tag: p
+    value: "<small>Last updated 3 mins ago</small>"
+    attributes:
+      class:
+        - card-text
+  links:
+    - type: html_tag
+      tag: a
+      value: "Card link"
+      attributes:
+        href: "#"
+    - type: html_tag
+      tag: a
+      value: "Another link"
+      attributes:
+        href: "#"
+props:
+  attributes:
+    class:
+      - text-bg-dark
+  heading_level: 5
diff --git a/templates/patterns/card_overlay/pattern-card-overlay.html.twig b/components/card_overlay/card_overlay.twig
similarity index 100%
rename from templates/patterns/card_overlay/pattern-card-overlay.html.twig
rename to components/card_overlay/card_overlay.twig
diff --git a/components/carousel/carousel.component.yml b/components/carousel/carousel.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4a723097fe4a364e9772bbcb40deaadb44467af2
--- /dev/null
+++ b/components/carousel/carousel.component.yml
@@ -0,0 +1,51 @@
+name: Carousel
+description: "A slideshow component for cycling through elements, like a carousel."
+group: Carousel
+links:
+  - "https://getbootstrap.com/docs/5.3/components/carousel/"
+variants:
+  default:
+    title: Default
+  fade:
+    title: Crossfade
+    description: "Animate slides with a fade transition instead of a slide."
+  dark:
+    title: "Dark (deprecated)"
+    description: "For darker controls, indicators, and captions."
+  fade__dark:
+    title: "Crossfade dark (deprecated)"
+slots:
+  slides:
+    title: Slides
+    description: "Each slide is a collection of carousel items."
+props:
+  type: object
+  properties:
+    with_controls:
+      title: "With controls?"
+      description: "Adding in the previous and next controls."
+      type: boolean
+    with_indicators:
+      title: "With indicators?"
+      description: "You can also add the indicators to the carousel, alongside the controls, too."
+      type: boolean
+    with_touch:
+      title: "With touch swiping?"
+      description: "Carousels support swiping left/right on touchscreen devices to move between slides."
+      type: boolean
+      default: true
+    interval:
+      title: Interval
+      description: "The amount of time to delay between automatically cycling to the next item. In ms. 0 to disable autoplay."
+      type: number
+      default: 5000
+    carousel_id:
+      title: ID
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+libraryOverrides:
+  js:
+    js/carousel.js: {}
+  dependencies:
+    - core/drupal
+    - core/once
diff --git a/components/carousel/carousel.preview.story.yml b/components/carousel/carousel.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..200c962c7ae8598a563f5d9eb7c48c9b1fb7254e
--- /dev/null
+++ b/components/carousel/carousel.preview.story.yml
@@ -0,0 +1,49 @@
+name: Preview
+slots:
+  slides:
+    - type: component
+      component: "ui_suite_bootstrap:carousel_item"
+      slots:
+        image:
+          theme: image
+          uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEZpcnN0IHNsaWRlIj48dGl0bGU+UGxhY2Vob2xkZXI8L3RpdGxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiM3NzciPjwvcmVjdD48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZmlsbD0iIzU1NSIgZHk9Ii4zZW0iPkZpcnN0IHNsaWRlPC90ZXh0Pjwvc3ZnPgo="
+        caption:
+          - type: html_tag
+            tag: h5
+            value: "First slide label"
+          - type: html_tag
+            tag: p
+            value: "Nulla vitae elit libero, a pharetra augue mollis interdum."
+    - type: component
+      component: "ui_suite_bootstrap:carousel_item"
+      slots:
+        image:
+          theme: image
+          uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IFNlY29uZCBzbGlkZSI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjNjY2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiM0NDQiIGR5PSIuM2VtIj5TZWNvbmQgc2xpZGU8L3RleHQ+PC9zdmc+Cg=="
+        caption:
+          - type: html_tag
+            tag: h5
+            value: "Second slide label"
+          - type: html_tag
+            tag: p
+            value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
+      props:
+        interval: 10000
+    - type: component
+      component: "ui_suite_bootstrap:carousel_item"
+      slots:
+        image:
+          theme: image
+          uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IFRoaXJkIHNsaWRlIj48dGl0bGU+UGxhY2Vob2xkZXI8L3RpdGxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiM1NTUiPjwvcmVjdD48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZmlsbD0iIzMzMyIgZHk9Ii4zZW0iPlRoaXJkIHNsaWRlPC90ZXh0Pjwvc3ZnPgo="
+        caption:
+          - type: html_tag
+            tag: h5
+            value: "Third slide label"
+          - type: html_tag
+            tag: p
+            value: "Praesent commodo cursus magna, vel scelerisque nisl consectetur."
+props:
+  with_controls: true
+  with_indicators: true
+  with_touch: true
+  interval: 5000
diff --git a/components/carousel/carousel.twig b/components/carousel/carousel.twig
new file mode 100644
index 0000000000000000000000000000000000000000..cab173c699a67446f9b4d05dc6fc656627390938
--- /dev/null
+++ b/components/carousel/carousel.twig
@@ -0,0 +1,57 @@
+{% if variant and variant|lower != 'default' %}
+  {% set variants = variant|split('__')|map(v => v|lower|replace({(v): 'carousel-' ~ v})|replace({'_': '-'})) %}
+  {% set attributes = attributes.addClass(variants) %}
+{% endif %}
+{% set attributes = 'dark' in variant|lower ? attributes.setAttribute('data-bs-theme', 'dark') : attributes %}
+
+{% if not with_touch %}
+  {% set attributes = attributes.setAttribute('data-bs-touch', 'false') %}
+{% endif %}
+
+{% set interval = interval|default(5000) %}
+{% set data_bs_ride = 'carousel' %}
+{% if interval == 0 %}
+  {% set interval = 'false' %}
+  {% set data_bs_ride = false %}
+{% endif %}
+{% set attributes = attributes.setAttribute('data-bs-interval', interval) %}
+{% set attributes = attributes.setAttribute('data-bs-ride', data_bs_ride) %}
+{% set carousel_id = carousel_id|default("carousel-" ~ random()) %}
+{% set slides = slides and slides is not sequence ? [slides] : slides %}
+
+{% if slides %}
+  <div{{ attributes.addClass('carousel').addClass('slide').setAttribute('id', carousel_id) }}>
+
+    {% if with_indicators %}
+    <div class="carousel-indicators">
+      {% for i in range(1, slides|length) %}
+      <button type="button"
+              data-bs-target="#{{ carousel_id }}"
+              data-bs-slide-to="{{ loop.index0 }}"
+              aria-label="{{ 'Slide @slide_number'|t({'@slide_number': i}) }}"
+        {% if loop.first %}
+        class="active"
+        aria-current="true"
+        {% endif %}>
+      </button>
+      {% endfor %}
+    </div>
+    {% endif %}
+
+    <div class="carousel-inner">
+      {{ slides }}
+    </div>
+
+    {% if with_controls %}
+    <button class="carousel-control-prev" type="button" data-bs-target="#{{ carousel_id }}" data-bs-slide="prev">
+      <span class="carousel-control-prev-icon" aria-hidden="true"></span>
+      <span class="visually-hidden">{{ 'Previous'|t }}</span>
+    </button>
+    <button class="carousel-control-next" type="button" data-bs-target="#{{ carousel_id }}" data-bs-slide="next">
+      <span class="carousel-control-next-icon" aria-hidden="true"></span>
+      <span class="visually-hidden">{{ 'Next'|t }}</span>
+    </button>
+    {% endif %}
+
+  </div>
+{% endif %}
diff --git a/components/carousel/js/carousel.js b/components/carousel/js/carousel.js
new file mode 100644
index 0000000000000000000000000000000000000000..4627689ed771f170386d622bdccb09c1528a646b
--- /dev/null
+++ b/components/carousel/js/carousel.js
@@ -0,0 +1,26 @@
+((Drupal, once) => {
+  Drupal.ui_suite_bootstrap_carousel = Drupal.ui_suite_bootstrap_carousel || {};
+
+  /**
+   * Set active class on the first item.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behaviors for the active class.
+   */
+  Drupal.behaviors.ui_suite_bootstrap_carousel = {
+    attach(context) {
+      once('carousel-active', '.carousel', context).forEach((carousel) => {
+        const items = carousel.querySelectorAll(
+          '.carousel-inner .carousel-item',
+        );
+        if (items.length === 0) {
+          return;
+        }
+
+        items.item(0).classList.add('active');
+      });
+    },
+  };
+})(Drupal, once);
diff --git a/components/carousel_item/carousel_item.component.yml b/components/carousel_item/carousel_item.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7f52d530f34ba43ba85f11bc01d9f7832e2c53ea
--- /dev/null
+++ b/components/carousel_item/carousel_item.component.yml
@@ -0,0 +1,19 @@
+name: "(Carousel Item)"
+description: "Internal: to be used in the 'Carousel' component."
+group: Carousel
+links:
+  - "https://getbootstrap.com/docs/5.3/components/carousel/"
+slots:
+  image:
+    title: Image
+    description: "The image of the item."
+  caption:
+    title: Caption
+    description: "The caption of the item."
+props:
+  type: object
+  properties:
+    interval:
+      title: Interval
+      description: "The amount of time to delay between automatically cycling to the next item. In ms."
+      type: number
diff --git a/templates/patterns/carousel_item/pattern-carousel-item.html.twig b/components/carousel_item/carousel_item.twig
similarity index 78%
rename from templates/patterns/carousel_item/pattern-carousel-item.html.twig
rename to components/carousel_item/carousel_item.twig
index 13b2027f27729a2d513f6e8a56eaf79032310759..dcf213e3f49ab566950f6d4fed60f6dcf57b074f 100644
--- a/templates/patterns/carousel_item/pattern-carousel-item.html.twig
+++ b/components/carousel_item/carousel_item.twig
@@ -1,4 +1,3 @@
-{% set attributes = active ? attributes.addClass('active') : attributes %}
 {% set attributes = interval ? attributes.setAttribute('data-bs-interval', interval) : attributes %}
 
 <div{{ attributes.addClass('carousel-item') }}>
diff --git a/components/close_button/close_button.component.yml b/components/close_button/close_button.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..44d6501641e4d224ed4f0c60e5753051719ed449
--- /dev/null
+++ b/components/close_button/close_button.component.yml
@@ -0,0 +1,21 @@
+name: "Close button"
+description: "A generic close button for dismissing content like modals and alerts."
+group: Button
+links:
+  - "https://getbootstrap.com/docs/5.3/components/close-button"
+variants:
+  default:
+    title: Default
+  white:
+    title: "White (deprecated)"
+props:
+  type: object
+  properties:
+    disabled:
+      title: "Disabled?"
+      description: "Is the button disabled?"
+      type: boolean
+    aria_label:
+      title: "Aria label"
+      description: "Name of the close button for assistive technology."
+      type: string
diff --git a/components/close_button/close_button.dark.story.yml b/components/close_button/close_button.dark.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..707d9f3d21971e5d836ebc6d35f33925f708a955
--- /dev/null
+++ b/components/close_button/close_button.dark.story.yml
@@ -0,0 +1,6 @@
+name: Dark
+props:
+  variant: default
+  disabled: false
+  aria_label: Close
+library_wrapper: "<div class=\"bg-dark\" data-bs-theme=\"dark\">{{ _story }}</div"
diff --git a/components/close_button/close_button.preview.story.yml b/components/close_button/close_button.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9c95156ebf9ca3b2c19beba45a588c6d150a00aa
--- /dev/null
+++ b/components/close_button/close_button.preview.story.yml
@@ -0,0 +1,5 @@
+name: Preview
+props:
+  variant: default
+  disabled: false
+  aria_label: Close
diff --git a/templates/patterns/close_button/pattern-close-button.html.twig b/components/close_button/close_button.twig
similarity index 100%
rename from templates/patterns/close_button/pattern-close-button.html.twig
rename to components/close_button/close_button.twig
diff --git a/components/close_button/close_button.white.story.yml b/components/close_button/close_button.white.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..30820780e3d04dd250dc89566fb019122f7d3b1d
--- /dev/null
+++ b/components/close_button/close_button.white.story.yml
@@ -0,0 +1,6 @@
+name: "White (deprecated)"
+props:
+  variant: white
+  disabled: false
+  aria_label: Close
+library_wrapper: "<div class=\"bg-dark\">{{ _story }}</div"
diff --git a/templates/patterns/dropdown/dropdown.ui_patterns.yml b/components/dropdown/dropdown.component.yml
similarity index 50%
rename from templates/patterns/dropdown/dropdown.ui_patterns.yml
rename to components/dropdown/dropdown.component.yml
index 14d17bfec8cb85ebd90df19e32b497339e9ad70f..830580516dd73f06accbf800e19b54892dfa03c4 100644
--- a/templates/patterns/dropdown/dropdown.ui_patterns.yml
+++ b/components/dropdown/dropdown.component.yml
@@ -1,65 +1,103 @@
-dropdown:
-  label: "Dropdown"
-  description: "Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They’re made interactive with the included Bootstrap dropdown JavaScript plugin. They’re toggled by clicking, not by hovering; this is an intentional design decision."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/dropdowns/'
-  category: "Dropdown"
-  variants:
-    dropdown:
-      label: "Dropdown (Default)"
-    dropdown_center:
-      label: "Centered dropdown"
-    dropup:
-      label: "Dropup"
-    dropup_center:
-      label: "Centered dropup"
-    dropend:
-      label: "Dropend"
-    dropstart:
-      label: "Dropstart"
-  settings:
+name: Dropdown
+description: "Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They’re made interactive with the included Bootstrap dropdown JavaScript plugin. They’re toggled by clicking, not by hovering; this is an intentional design decision."
+group: Dropdown
+links:
+  - "https://getbootstrap.com/docs/5.3/components/dropdowns/"
+variants:
+  dropdown:
+    title: "Dropdown (Default)"
+  dropdown_center:
+    title: "Centered dropdown"
+  dropup:
+    title: Dropup
+  dropup_center:
+    title: "Centered dropup"
+  dropend:
+    title: Dropend
+  dropstart:
+    title: Dropstart
+slots:
+  title:
+    title: Title
+    description: "The dropdown button title. Plain text."
+props:
+  type: object
+  properties:
     content:
-      type: "links"
-      label: "Content"
+      title: Content
       description: "If a link does not have a URL, it renders as: a header if it has the 'dropdown-header' class; a button if it has the 'dropdown-item' class; else a text. If a link does not have a url and a title or has the 'dropdown-divider' class, it renders as a divider."
-      preview:
-        - title: "Dropdown header"
-          link_attributes:
-            class: [dropdown-header]
-        - title: "Action"
-          url: '#'
-        - title: "Dropdown item text"
-        - title: "Another action"
-          url: '#'
-        - title: "Something else here"
-          url: '#'
-        - {}
-        - title: "Separated link"
-          url: '#'
-        - title: "Action (button)"
-          link_attributes:
-            class: [dropdown-item]
-        - title: "Another action (button)"
-          link_attributes:
-            class: [dropdown-item]
-        - title: "Something else here (text)"
+      $ref: "ui-patterns://links"
     dropdown_id:
-      type: "textfield"
-      label: "ID"
+      title: ID
       description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
     button_variant:
-      type: "select"
-      label: "Button variant"
-      options:
+      title: "Button variant"
+      type: string
+      enum:
+        - default
+        - primary
+        - secondary
+        - success
+        - danger
+        - warning
+        - info
+        - light
+        - dark
+        - link
+        - primary__sm
+        - secondary__sm
+        - success__sm
+        - danger__sm
+        - warning__sm
+        - info__sm
+        - light__sm
+        - dark__sm
+        - link__sm
+        - primary__lg
+        - secondary__lg
+        - success__lg
+        - danger__lg
+        - warning__lg
+        - info__lg
+        - light__lg
+        - dark__lg
+        - link__lg
+        - outline_primary__sm
+        - outline_secondary__sm
+        - outline_success__sm
+        - outline_danger__sm
+        - outline_warning__sm
+        - outline_info__sm
+        - outline_light__sm
+        - outline_dark__sm
+        - outline_primary
+        - outline_secondary
+        - outline_success
+        - outline_danger
+        - outline_warning
+        - outline_info
+        - outline_light
+        - outline_dark
+        - outline_primary__lg
+        - outline_secondary__lg
+        - outline_success__lg
+        - outline_danger__lg
+        - outline_warning__lg
+        - outline_info__lg
+        - outline_light__lg
+        - outline_dark__lg
+      "meta:enum":
+        default: Default
         primary: "Primary (default)"
-        secondary: "Secondary"
-        success: "Success"
-        danger: "Danger"
-        warning: "Warning"
-        info: "Info"
-        light: "Light"
-        dark: "Dark"
-        link: "Link"
+        secondary: Secondary
+        success: Success
+        danger: Danger
+        warning: Warning
+        info: Info
+        light: Light
+        dark: Dark
+        link: Link
         primary__sm: "Primary small"
         secondary__sm: "Secondary small"
         success__sm: "Success small"
@@ -102,96 +140,87 @@ dropdown:
         outline_info__lg: "Outline Info large"
         outline_light__lg: "Outline Light large"
         outline_dark__lg: "Outline Dark large"
-      allow_expose: true
-      allow_token: true
-      preview: primary
-      default: primary
     button_split:
-      type: "boolean"
-      label: "Split"
+      title: Split
       description: "Create split button dropdowns with virtually the same markup as single button dropdowns, but with the addition of .dropdown-toggle-split for proper spacing around the dropdown caret."
-      preview: true
-      allow_expose: true
-      allow_token: true
+      type: boolean
     button_url:
-      label: "Button URL"
-      type: url
-      preview: "/"
+      title: "Button URL"
+      $ref: "ui-patterns://url"
     button_attributes:
-      type: "attributes"
-      label: "Button attributes"
+      title: "Button attributes"
       description: "The attributes to customize the dropdown button."
-      preview: ''
-      allow_expose: true
+      $ref: "ui-patterns://attributes"
     dark:
-      type: "boolean"
-      label: "Dark (deprecated)"
+      title: "Dark (deprecated)"
       description: "Opt into darker dropdowns to match a dark navbar or custom style."
-      preview: false
-      allow_expose: true
-      allow_token: true
+      type: boolean
     auto_close:
-      type: "select"
-      label: "Auto close"
+      title: "Auto close"
       description: "By default, the dropdown menu is closed when clicking inside or outside the dropdown menu. You can use the autoClose option to change this behavior of the dropdown."
-      options:
-        'true': "Default"
-        'inside': "When click inside"
-        'outside': "When click outside"
-        'false': "Manual close"
-      preview: "true"
-      allow_expose: true
-      allow_token: true
+      type: string
+      enum:
+        - "true"
+        - inside
+        - outside
+        - "false"
+      "meta:enum":
+        "true": Default
+        inside: "When click inside"
+        outside: "When click outside"
+        "false": "Manual close"
     dropdown_navbar:
-      type: "boolean"
-      label: "Use in navbar?"
+      title: "Use in navbar?"
       description: "Check if the dropdown will be used in a navbar-nav element."
-      preview: false
-      allow_expose: true
-      allow_token: true
+      type: boolean
     dropdown_menu_start:
-      type: "select"
-      label: "Menu alignment: start"
+      title: "Menu alignment: start"
       description: "To align left/start the dropdown menu with the given breakpoint or larger."
-      options:
-        start: "all"
+      type: string
+      enum:
+        - start
+        - sm-start
+        - md-start
+        - lg-start
+        - xl-start
+        - xxl-start
+      "meta:enum":
+        start: all
         sm-start: "from small"
         md-start: "from medium"
         lg-start: "from large"
         xl-start: "from extra large"
         xxl-start: "from extra extra large"
-      preview: ''
-      allow_expose: true
-      allow_token: true
     dropdown_menu_end:
-      type: "select"
-      label: "Menu alignment: end"
+      title: "Menu alignment: end"
       description: "To align right/end the dropdown menu with the given breakpoint or larger."
-      options:
-        end: "all"
+      type: string
+      enum:
+        - end
+        - sm-end
+        - md-end
+        - lg-end
+        - xl-end
+        - xxl-end
+      "meta:enum":
+        end: all
         sm-end: "from small"
         md-end: "from medium"
         lg-end: "from large"
         xl-end: "from extra large"
         xxl-end: "from extra extra large"
-      preview: ''
-      allow_expose: true
-      allow_token: true
     heading_level:
-      type: "select"
-      label: "Heading level for header items"
-      options:
-        2: "h2"
-        3: "h3"
-        4: "h4"
-        5: "h5"
+      title: "Heading level for header items"
+      type: integer
+      enum:
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        2: h2
+        3: h3
+        4: h4
+        5: h5
         6: "h6 (Default)"
-      preview: 6
-      allow_expose: true
-      allow_token: true
-  fields:
-    title:
-      type: "text"
-      label: "Title"
-      description: "The dropdown button title. Plain text."
-      preview: "Button"
diff --git a/components/dropdown/dropdown.preview.story.yml b/components/dropdown/dropdown.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8e42f73abf2b58d5917a459aef91752423676151
--- /dev/null
+++ b/components/dropdown/dropdown.preview.story.yml
@@ -0,0 +1,36 @@
+name: Preview
+slots:
+  title: Button
+props:
+  content:
+    - title: "Dropdown header"
+      link_attributes:
+        class:
+          - dropdown-header
+    - title: Action
+      url: "#"
+    - title: "Dropdown item text"
+    - title: "Another action"
+      url: "#"
+    - title: "Something else here"
+      url: "#"
+    - {}
+    - title: "Separated link"
+      url: "#"
+    - title: "Action (button)"
+      link_attributes:
+        class:
+          - dropdown-item
+    - title: "Another action (button)"
+      link_attributes:
+        class:
+          - dropdown-item
+    - title: "Something else here (text)"
+  button_variant: primary
+  button_split: true
+  button_url: /
+  button_attributes: {}
+  dark: false
+  auto_close: "true"
+  dropdown_navbar: false
+  heading_level: 6
diff --git a/templates/patterns/dropdown/pattern-dropdown.html.twig b/components/dropdown/dropdown.twig
similarity index 93%
rename from templates/patterns/dropdown/pattern-dropdown.html.twig
rename to components/dropdown/dropdown.twig
index d9279f5b32bfcb23495936af7362309718920542..3630a3c11c6c7a30deaf869ec657e7222b3b3603 100644
--- a/templates/patterns/dropdown/pattern-dropdown.html.twig
+++ b/components/dropdown/dropdown.twig
@@ -31,25 +31,27 @@
 <{{ dropdown_tag }}{{ attributes.addClass(variant) }}>
 
 {% if button_split %}
-  {{ pattern('button', {
-    variant: button_variant,
+  {{ include('ui_suite_bootstrap:button', {
     label: title,
-    url: button_url,
-    attributes: create_attribute().setAttribute('id', dropdown_id)
-  }) }}
-  {{ pattern('button', {
+    attributes: {
+      id: dropdown_id,
+    },
     variant: button_variant,
+    url: button_url,
+  }, with_context = false) }}
+  {{ include('ui_suite_bootstrap:button', {
     label: 'Toggle dropdown'|t,
+    attributes: button_attributes.addClass('dropdown-toggle-split'),
+    variant: button_variant,
     label_visually_hidden: true,
-    attributes: button_attributes.addClass('dropdown-toggle-split')
-  }) }}
+  }, with_context = false) }}
 {% else %}
-  {{ pattern('button', {
-    variant: button_variant,
+  {{ include('ui_suite_bootstrap:button', {
     label: title,
+    attributes: button_attributes.setAttribute('id', dropdown_id),
+    variant: button_variant,
     url: button_url,
-    attributes: button_attributes.setAttribute('id', dropdown_id)
-  }) }}
+  }, with_context = false) }}
 {% endif %}
 
   {% if content %}
diff --git a/components/figure/figure.component.yml b/components/figure/figure.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d2235f76a84d00f886b3bccb22fa8bb6e1d7fe66
--- /dev/null
+++ b/components/figure/figure.component.yml
@@ -0,0 +1,18 @@
+name: Figure
+description: "Used to display a piece of self-contained content (illustrations, diagrams, photos, code, etc) along with an optional caption. This content can be removed from the document without affecting the meaning of the document."
+links:
+  - "https://getbootstrap.com/docs/5.3/content/figures/"
+slots:
+  image:
+    title: Image
+    description: "The content of the figure."
+  caption:
+    title: Caption
+    description: "The caption that appears under the content."
+props:
+  type: object
+  properties:
+    figcaption_attributes:
+      title: "Figcaption attributes"
+      description: "The attributes to customize the figcaption tag."
+      $ref: "ui-patterns://attributes"
diff --git a/components/figure/figure.preview.story.yml b/components/figure/figure.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..be5cf179ab4b448e39916d02a1546053834b4ccb
--- /dev/null
+++ b/components/figure/figure.preview.story.yml
@@ -0,0 +1,10 @@
+name: Preview
+slots:
+  image:
+    theme: image
+    uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
+    alt: "&copy; 2017 John Smith photography"
+  caption: "A caption for the above image."
+props:
+  figcaption_attributes:
+    class: text-end
diff --git a/templates/patterns/figure/pattern-figure.html.twig b/components/figure/figure.twig
similarity index 100%
rename from templates/patterns/figure/pattern-figure.html.twig
rename to components/figure/figure.twig
diff --git a/components/grid_row/grid_row.component.yml b/components/grid_row/grid_row.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4486a17f24963a6645c5661366e64f9131014d9a
--- /dev/null
+++ b/components/grid_row/grid_row.component.yml
@@ -0,0 +1,423 @@
+name: "Grid Row"
+description: "The grid system uses a series of containers, rows, and columns to layout and align content. For simple use cases only. For more powerful needs, use grid_row_* components. Use the container attributes, row attributes (= component attributes) and/or col attributes to set responsive declinations of classes and/or classes already declared by styles."
+group: Layout
+icon_map:
+  - [main, second, third, fourth]
+links:
+  - url: 'https://getbootstrap.com/docs/5.3/layout/containers/'
+    title: 'See container documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/grid/'
+    title: 'See grid documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/columns/'
+    title: 'See columns documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/gutters/'
+    title: 'See gutters documentation'
+slots:
+  content:
+    title: Content
+    description: "The content of each column."
+props:
+  type: object
+  properties:
+    with_container:
+      title: "With container? (deprecated)"
+      description: "Use the container option instead."
+      type: boolean
+    container:
+      title: Container
+      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
+      type: string
+      enum:
+        - container
+        - container-sm
+        - container-md
+        - container-lg
+        - container-xl
+        - container-xxl
+        - container-fluid
+      "meta:enum":
+        container: Container
+        container-sm: "Container small"
+        container-md: "Container medium"
+        container-lg: "Container large"
+        container-xl: "Container x-large"
+        container-xxl: "Container xx-large"
+        container-fluid: "Container fluid"
+    container_attributes:
+      title: "Container attributes"
+      description: "The attributes to customize the tag with the container class if present."
+      $ref: "ui-patterns://attributes"
+    container_wrapper_attributes:
+      title: "Container wrapper attributes"
+      description: "The attributes to customize a div tag above the container class if present."
+      $ref: "ui-patterns://attributes"
+    gutters:
+      title: Gutters
+      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
+      type: string
+      enum:
+        - g-0
+        - g-1
+        - g-2
+        - g-3
+        - g-4
+        - g-5
+      "meta:enum":
+        g-0: "0"
+        g-1: "1"
+        g-2: "2"
+        g-3: "3"
+        g-4: "4"
+        g-5: "5"
+    gutters_horizontal:
+      title: "Horizontal gutters"
+      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
+      type: string
+      enum:
+        - gx-0
+        - gx-1
+        - gx-2
+        - gx-3
+        - gx-4
+        - gx-5
+      "meta:enum":
+        gx-0: "0"
+        gx-1: "1"
+        gx-2: "2"
+        gx-3: "3"
+        gx-4: "4"
+        gx-5: "5"
+    gutters_vertical:
+      title: "Vertical gutters"
+      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
+      type: string
+      enum:
+        - gy-0
+        - gy-1
+        - gy-2
+        - gy-3
+        - gy-4
+        - gy-5
+      "meta:enum":
+        gy-0: "0"
+        gy-1: "1"
+        gy-2: "2"
+        gy-3: "3"
+        gy-4: "4"
+        gy-5: "5"
+    row_cols:
+      title: "Row columns"
+      description: "Use theses classes to quickly set the number of columns that best render your content and layout. With 'Auto' you can give the columns their natural width."
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xs:
+      title: "All (Extra small)"
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-1"
+        - "col-2"
+        - "col-3"
+        - "col-4"
+        - "col-5"
+        - "col-6"
+        - "col-7"
+        - "col-8"
+        - "col-9"
+        - "col-10"
+        - "col-11"
+        - "col-12"
+      "meta:enum":
+        auto: "Auto"
+        col-1: "1 (deprecated)"
+        col-2: "2 (deprecated)"
+        col-3: "3 (deprecated)"
+        col-4: "4 (deprecated)"
+        col-5: "5 (deprecated)"
+        col-6: "6 (deprecated)"
+        col-7: "7 (deprecated)"
+        col-8: "8 (deprecated)"
+        col-9: "9 (deprecated)"
+        col-10: "10 (deprecated)"
+        col-11: "11 (deprecated)"
+        col-12: "12 (deprecated)"
+    col_sm:
+      title: Small
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-sm-1"
+        - "col-sm-2"
+        - "col-sm-3"
+        - "col-sm-4"
+        - "col-sm-5"
+        - "col-sm-6"
+        - "col-sm-7"
+        - "col-sm-8"
+        - "col-sm-9"
+        - "col-sm-10"
+        - "col-sm-11"
+        - "col-sm-12"
+      "meta:enum":
+        auto: "Auto"
+        col-sm-1: "1 (deprecated)"
+        col-sm-2: "2 (deprecated)"
+        col-sm-3: "3 (deprecated)"
+        col-sm-4: "4 (deprecated)"
+        col-sm-5: "5 (deprecated)"
+        col-sm-6: "6 (deprecated)"
+        col-sm-7: "7 (deprecated)"
+        col-sm-8: "8 (deprecated)"
+        col-sm-9: "9 (deprecated)"
+        col-sm-10: "10 (deprecated)"
+        col-sm-11: "11 (deprecated)"
+        col-sm-12: "12 (deprecated)"
+    col_md:
+      title: Medium
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-md-1"
+        - "col-md-2"
+        - "col-md-3"
+        - "col-md-4"
+        - "col-md-5"
+        - "col-md-6"
+        - "col-md-7"
+        - "col-md-8"
+        - "col-md-9"
+        - "col-md-10"
+        - "col-md-11"
+        - "col-md-12"
+      "meta:enum":
+        auto: "Auto"
+        col-md-1: "1 (deprecated)"
+        col-md-2: "2 (deprecated)"
+        col-md-3: "3 (deprecated)"
+        col-md-4: "4 (deprecated)"
+        col-md-5: "5 (deprecated)"
+        col-md-6: "6 (deprecated)"
+        col-md-7: "7 (deprecated)"
+        col-md-8: "8 (deprecated)"
+        col-md-9: "9 (deprecated)"
+        col-md-10: "10 (deprecated)"
+        col-md-11: "11 (deprecated)"
+        col-md-12: "12 (deprecated)"
+    col_lg:
+      title: Large
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-lg-1"
+        - "col-lg-2"
+        - "col-lg-3"
+        - "col-lg-4"
+        - "col-lg-5"
+        - "col-lg-6"
+        - "col-lg-7"
+        - "col-lg-8"
+        - "col-lg-9"
+        - "col-lg-10"
+        - "col-lg-11"
+        - "col-lg-12"
+      "meta:enum":
+        auto: "Auto"
+        col-lg-1: "1 (deprecated)"
+        col-lg-2: "2 (deprecated)"
+        col-lg-3: "3 (deprecated)"
+        col-lg-4: "4 (deprecated)"
+        col-lg-5: "5 (deprecated)"
+        col-lg-6: "6 (deprecated)"
+        col-lg-7: "7 (deprecated)"
+        col-lg-8: "8 (deprecated)"
+        col-lg-9: "9 (deprecated)"
+        col-lg-10: "10 (deprecated)"
+        col-lg-11: "11 (deprecated)"
+        col-lg-12: "12 (deprecated)"
+    col_xl:
+      title: "Extra large"
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-xl-1"
+        - "col-xl-2"
+        - "col-xl-3"
+        - "col-xl-4"
+        - "col-xl-5"
+        - "col-xl-6"
+        - "col-xl-7"
+        - "col-xl-8"
+        - "col-xl-9"
+        - "col-xl-10"
+        - "col-xl-11"
+        - "col-xl-12"
+      "meta:enum":
+        auto: "Auto"
+        col-xl-1: "1 (deprecated)"
+        col-xl-2: "2 (deprecated)"
+        col-xl-3: "3 (deprecated)"
+        col-xl-4: "4 (deprecated)"
+        col-xl-5: "5 (deprecated)"
+        col-xl-6: "6 (deprecated)"
+        col-xl-7: "7 (deprecated)"
+        col-xl-8: "8 (deprecated)"
+        col-xl-9: "9 (deprecated)"
+        col-xl-10: "10 (deprecated)"
+        col-xl-11: "11 (deprecated)"
+        col-xl-12: "12 (deprecated)"
+    col_xxl:
+      title: "Extra extra large"
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+        - "col-xxl-1"
+        - "col-xxl-2"
+        - "col-xxl-3"
+        - "col-xxl-4"
+        - "col-xxl-5"
+        - "col-xxl-6"
+        - "col-xxl-7"
+        - "col-xxl-8"
+        - "col-xxl-9"
+        - "col-xxl-10"
+        - "col-xxl-11"
+        - "col-xxl-12"
+      "meta:enum":
+        auto: "Auto"
+        col-xxl-1: "1 (deprecated)"
+        col-xxl-2: "2 (deprecated)"
+        col-xxl-3: "3 (deprecated)"
+        col-xxl-4: "4 (deprecated)"
+        col-xxl-5: "5 (deprecated)"
+        col-xxl-6: "6 (deprecated)"
+        col-xxl-7: "7 (deprecated)"
+        col-xxl-8: "8 (deprecated)"
+        col-xxl-9: "9 (deprecated)"
+        col-xxl-10: "10 (deprecated)"
+        col-xxl-11: "11 (deprecated)"
+        col-xxl-12: "12 (deprecated)"
+    col_offset:
+      title: "Offset"
+      type: integer
+      enum:
+        - 1
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+        - 7
+        - 8
+        - 9
+        - 10
+        - 11
+    spacing_margin_bottom:
+      title: "Cols margin bottom (deprecated)"
+      type: string
+      enum:
+        - mb-0
+        - mb-1
+        - mb-2
+        - mb-3
+        - mb-4
+        - mb-5
+        - mb-auto
+      "meta:enum":
+        mb-0: "0"
+        mb-1: "1"
+        mb-2: "2"
+        mb-3: "3"
+        mb-4: "4"
+        mb-5: "5"
+        mb-auto: Auto
+    col_attributes:
+      title: "Column attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
diff --git a/components/grid_row/grid_row.preview.story.yml b/components/grid_row/grid_row.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bee7231b2e26b91ac1f41d124b2913ee86ba698a
--- /dev/null
+++ b/components/grid_row/grid_row.preview.story.yml
@@ -0,0 +1,27 @@
+name: Preview
+slots:
+  content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+props:
+  gutters: g-0
+  col_xs: 12
+  col_md: 3
diff --git a/components/grid_row/grid_row.twig b/components/grid_row/grid_row.twig
new file mode 100644
index 0000000000000000000000000000000000000000..bc4b531df7a470dcd78447fde63c456ee88b3e52
--- /dev/null
+++ b/components/grid_row/grid_row.twig
@@ -0,0 +1,70 @@
+{# Deprecated options compatibility. #}
+{% if with_container and not container %}
+  {% set container = 'container' %}
+{% endif %}
+{% if col_xs and not (col_xs starts with 'col-') %}
+  {% set col_xs = 'col-' ~ col_xs %}
+{% endif %}
+{% if col_sm and not (col_sm starts with 'col-sm-') %}
+  {% set col_sm = 'col-sm-' ~ col_sm %}
+{% endif %}
+{% if col_md and not (col_md starts with 'col-md-') %}
+  {% set col_md = 'col-md-' ~ col_md %}
+{% endif %}
+{% if col_lg and not (col_lg starts with 'col-lg-') %}
+  {% set col_lg = 'col-lg-' ~ col_lg %}
+{% endif %}
+{% if col_xl and not (col_xl starts with 'col-xl-') %}
+  {% set col_xl = 'col-xl-' ~ col_xl %}
+{% endif %}
+{% if col_xxl and not (col_xxl starts with 'col-xxl-') %}
+  {% set col_xxl = 'col-xxl-' ~ col_xxl %}
+{% endif %}
+
+{% set container_wrapper_attributes = create_attribute(container_wrapper_attributes|default({})) %}
+{% set container_attributes = create_attribute(container_attributes|default({})) %}
+{% set col_attributes = create_attribute(col_attributes|default({})) %}
+
+{% set attributes = attributes.addClass([
+  'row',
+  gutters,
+  gutters_horizontal,
+  gutters_vertical,
+  row_cols ? 'row-cols-' ~ row_cols,
+]) %}
+
+{% set col_attributes = col_attributes.addClass([
+  'col',
+  col_xs,
+  col_sm,
+  col_md,
+  col_lg,
+  col_xl,
+  col_xxl,
+  spacing_margin_bottom,
+  col_offset ? 'offset-' ~ col_offset,
+]) %}
+
+{% set content = content and content is not sequence ? [content] : content %}
+
+{% if container %}
+  {% if container_wrapper_attributes.storage() %}
+  <div{{ container_wrapper_attributes }}>
+  {% endif %}
+  <div{{ container_attributes.addClass(container) }}>
+{% endif %}
+
+  <div{{ attributes }}>
+    {% for item in content %}
+      <div{{ col_attributes }}>
+        {{ item }}
+      </div>
+    {% endfor %}
+  </div>
+
+{% if container %}
+  </div>
+  {% if container_wrapper_attributes.storage() %}
+  </div>
+  {% endif %}
+{% endif %}
diff --git a/components/grid_row_1/grid_row_1.component.yml b/components/grid_row_1/grid_row_1.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3c8d8e6c94a1dfc6b581556583d51464525bf036
--- /dev/null
+++ b/components/grid_row_1/grid_row_1.component.yml
@@ -0,0 +1,257 @@
+name: "Grid Row 1 Col (Bootstrap)"
+description: "The grid system uses a series of containers, rows, and columns to layout and align content. Use the container attributes, row attributes (= component attributes) and/or col attributes to set responsive declinations of classes and/or classes already declared by styles."
+group: Layout
+icon_map:
+  - [main]
+links:
+  - url: 'https://getbootstrap.com/docs/5.3/layout/containers/'
+    title: 'See container documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/grid/'
+    title: 'See grid documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/columns/'
+    title: 'See columns documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/gutters/'
+    title: 'See gutters documentation'
+slots:
+  col_1_content:
+    title: "Col 1 content"
+    description: "The content of the column 1."
+props:
+  type: object
+  properties:
+    container:
+      title: Container
+      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
+      type: string
+      enum:
+        - container
+        - container-sm
+        - container-md
+        - container-lg
+        - container-xl
+        - container-xxl
+        - container-fluid
+      "meta:enum":
+        container: Container
+        container-sm: "Container small"
+        container-md: "Container medium"
+        container-lg: "Container large"
+        container-xl: "Container x-large"
+        container-xxl: "Container xx-large"
+        container-fluid: "Container fluid"
+    container_attributes:
+      title: "Container attributes"
+      description: "The attributes to customize the tag with the container class if present."
+      $ref: "ui-patterns://attributes"
+    container_wrapper_attributes:
+      title: "Container wrapper attributes"
+      description: "The attributes to customize a div tag above the container class if present."
+      $ref: "ui-patterns://attributes"
+    gutters:
+      title: Gutters
+      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
+      type: string
+      enum:
+        - g-0
+        - g-1
+        - g-2
+        - g-3
+        - g-4
+        - g-5
+      "meta:enum":
+        g-0: "0"
+        g-1: "1"
+        g-2: "2"
+        g-3: "3"
+        g-4: "4"
+        g-5: "5"
+    gutters_horizontal:
+      title: "Horizontal gutters"
+      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
+      type: string
+      enum:
+        - gx-0
+        - gx-1
+        - gx-2
+        - gx-3
+        - gx-4
+        - gx-5
+      "meta:enum":
+        gx-0: "0"
+        gx-1: "1"
+        gx-2: "2"
+        gx-3: "3"
+        gx-4: "4"
+        gx-5: "5"
+    gutters_vertical:
+      title: "Vertical gutters"
+      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
+      type: string
+      enum:
+        - gy-0
+        - gy-1
+        - gy-2
+        - gy-3
+        - gy-4
+        - gy-5
+      "meta:enum":
+        gy-0: "0"
+        gy-1: "1"
+        gy-2: "2"
+        gy-3: "3"
+        gy-4: "4"
+        gy-5: "5"
+    row_cols:
+      title: "Row columns"
+      description: "Use theses classes to quickly set the number of columns that best render your content and layout. With 'Auto' you can give the columns their natural width."
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xs:
+      title: "All (Extra small)"
+      type: string
+      default: 12
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_sm:
+      title: Small
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_md:
+      title: Medium
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_lg:
+      title: Large
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xl:
+      title: "Extra large"
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xxl:
+      title: "Extra extra large"
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_offset:
+      title: "Offset"
+      type: integer
+      enum:
+        - 1
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+        - 7
+        - 8
+        - 9
+        - 10
+        - 11
+    col_attributes:
+      title: "Column attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
diff --git a/components/grid_row_1/grid_row_1.preview.story.yml b/components/grid_row_1/grid_row_1.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c20a6e1edc16c63f9dec14fea3199863c332fdec
--- /dev/null
+++ b/components/grid_row_1/grid_row_1.preview.story.yml
@@ -0,0 +1,12 @@
+name: Preview
+slots:
+  col_1_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+props:
+  gutters: g-0
+  col_xs: 12
+  col_md: 3
diff --git a/components/grid_row_1/grid_row_1.twig b/components/grid_row_1/grid_row_1.twig
new file mode 100644
index 0000000000000000000000000000000000000000..4e3caeceb0613f0e61d1f3eab3482ad7c8707724
--- /dev/null
+++ b/components/grid_row_1/grid_row_1.twig
@@ -0,0 +1,44 @@
+{% set container_wrapper_attributes = create_attribute(container_wrapper_attributes|default({})) %}
+{% set container_attributes = create_attribute(container_attributes|default({})) %}
+{% set col_attributes = create_attribute(col_attributes|default({})) %}
+
+{% set attributes = attributes.addClass([
+  'row',
+  gutters,
+  gutters_horizontal,
+  gutters_vertical,
+  row_cols ? 'row-cols-' ~ row_cols,
+]) %}
+
+{% set col_attributes = col_attributes.addClass([
+  'col',
+  col_xs ? 'col-' ~ col_xs,
+  col_sm ? 'col-sm-' ~ col_sm,
+  col_md ? 'col-md-' ~ col_md,
+  col_lg ? 'col-lg-' ~ col_lg,
+  col_xl ? 'col-xl-' ~ col_xl,
+  col_xxl ? 'col-xxl-' ~ col_xxl,
+  col_offset ? 'offset-' ~ col_offset,
+]) %}
+
+{% set col_1_content = col_1_content and col_1_content is not sequence ? [col_1_content] : col_1_content %}
+
+{% if container %}
+  {% if container_wrapper_attributes.storage() %}
+  <div{{ container_wrapper_attributes }}>
+  {% endif %}
+  <div{{ container_attributes.addClass(container) }}>
+{% endif %}
+
+<div{{ attributes }}>
+  <div{{ col_attributes }}>
+    {{ col_1_content }}
+  </div>
+</div>
+
+{% if container %}
+  </div>
+    {% if container_wrapper_attributes.storage() %}
+  </div>
+  {% endif %}
+{% endif %}
diff --git a/components/grid_row_2/grid_row_2.component.yml b/components/grid_row_2/grid_row_2.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cb1fcea9ad45286b4024e6b59bddc6b3017eedca
--- /dev/null
+++ b/components/grid_row_2/grid_row_2.component.yml
@@ -0,0 +1,286 @@
+name: "Grid Row 2 Cols (Bootstrap)"
+description: "The grid system uses a series of containers, rows, and columns to layout and align content. Use the container attributes, row attributes (= component attributes) and/or col attributes to set responsive declinations of classes and/or classes already declared by styles."
+group: Layout
+icon_map:
+  - [main, second]
+links:
+  - url: 'https://getbootstrap.com/docs/5.3/layout/containers/'
+    title: 'See container documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/grid/'
+    title: 'See grid documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/columns/'
+    title: 'See columns documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/gutters/'
+    title: 'See gutters documentation'
+slots:
+  col_1_content:
+    title: "Col 1"
+    description: "The content of the column 1."
+  col_2_content:
+    title: "Col 2"
+    description: "The content of the column 2."
+props:
+  type: object
+  properties:
+    container:
+      title: Container
+      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
+      type: string
+      enum:
+        - container
+        - container-sm
+        - container-md
+        - container-lg
+        - container-xl
+        - container-xxl
+        - container-fluid
+      "meta:enum":
+        container: Container
+        container-sm: "Container small"
+        container-md: "Container medium"
+        container-lg: "Container large"
+        container-xl: "Container x-large"
+        container-xxl: "Container xx-large"
+        container-fluid: "Container fluid"
+    container_attributes:
+      title: "Container attributes"
+      description: "The attributes to customize the tag with the container class if present."
+      $ref: "ui-patterns://attributes"
+    container_wrapper_attributes:
+      title: "Container wrapper attributes"
+      description: "The attributes to customize a div tag above the container class if present."
+      $ref: "ui-patterns://attributes"
+    gutters:
+      title: Gutters
+      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
+      type: string
+      enum:
+        - g-0
+        - g-1
+        - g-2
+        - g-3
+        - g-4
+        - g-5
+      "meta:enum":
+        g-0: "0"
+        g-1: "1"
+        g-2: "2"
+        g-3: "3"
+        g-4: "4"
+        g-5: "5"
+    gutters_horizontal:
+      title: "Horizontal gutters"
+      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
+      type: string
+      enum:
+        - gx-0
+        - gx-1
+        - gx-2
+        - gx-3
+        - gx-4
+        - gx-5
+      "meta:enum":
+        gx-0: "0"
+        gx-1: "1"
+        gx-2: "2"
+        gx-3: "3"
+        gx-4: "4"
+        gx-5: "5"
+    gutters_vertical:
+      title: "Vertical gutters"
+      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
+      type: string
+      enum:
+        - gy-0
+        - gy-1
+        - gy-2
+        - gy-3
+        - gy-4
+        - gy-5
+      "meta:enum":
+        gy-0: "0"
+        gy-1: "1"
+        gy-2: "2"
+        gy-3: "3"
+        gy-4: "4"
+        gy-5: "5"
+    row_cols:
+      title: "Row columns"
+      description: "Use theses classes to quickly set the number of columns that best render your content and layout. With 'Auto' you can give the columns their natural width."
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xs:
+      title: "All (Extra small)"
+      type: array
+      maxItems: 2
+      default: [12, 12]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_sm:
+      title: Small
+      type: array
+      maxItems: 2
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_md:
+      title: Medium
+      type: array
+      maxItems: 2
+      default: [6, 6]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_lg:
+      title: Large
+      type: array
+      maxItems: 2
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xl:
+      title: "Extra large"
+      type: array
+      maxItems: 2
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xxl:
+      title: "Extra extra large"
+      type: array
+      maxItems: 2
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_offset:
+      title: "Offset"
+      type: array
+      maxItems: 2
+      items:
+        type: integer
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+          - 6
+          - 7
+          - 8
+          - 9
+          - 10
+          - 11
+    col_1_attributes:
+      title: "Column 1 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_2_attributes:
+      title: "Column 2 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
diff --git a/components/grid_row_2/grid_row_2.preview.story.yml b/components/grid_row_2/grid_row_2.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..05d80aa0056844b5214bb83967e75a33634f6a78
--- /dev/null
+++ b/components/grid_row_2/grid_row_2.preview.story.yml
@@ -0,0 +1,18 @@
+name: Preview
+slots:
+  col_1_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_2_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+props:
+  gutters: g-0
+  col_xs: [12, 12]
+  col_md: [6, 6]
diff --git a/components/grid_row_2/grid_row_2.twig b/components/grid_row_2/grid_row_2.twig
new file mode 100644
index 0000000000000000000000000000000000000000..d6ae2edb0629bd753ffac9150d2adc4a195eef04
--- /dev/null
+++ b/components/grid_row_2/grid_row_2.twig
@@ -0,0 +1,46 @@
+{% set container_wrapper_attributes = create_attribute(container_wrapper_attributes|default({})) %}
+{% set container_attributes = create_attribute(container_attributes|default({})) %}
+{% set col_attributes = [
+  create_attribute(col_1_attributes|default({})),
+  create_attribute(col_2_attributes|default({})),
+] %}
+
+{% set attributes = attributes.addClass([
+  'row',
+  gutters,
+  gutters_horizontal,
+  gutters_vertical,
+  row_cols ? 'row-cols-' ~ row_cols,
+]) %}
+
+{% if container %}
+  {% if container_wrapper_attributes.storage() %}
+  <div{{ container_wrapper_attributes }}>
+  {% endif %}
+  <div{{ container_attributes.addClass(container) }}>
+{% endif %}
+
+<div{{ attributes }}>
+  {% for region in [col_1_content, col_2_content] %}
+    {% set region = region and region is not sequence ? [region] : region %}
+    <div{{ col_attributes[loop.index0].addClass([
+      'col',
+      col_xs[loop.index0] ? 'col-' ~ col_xs[loop.index0],
+      col_sm[loop.index0] ? 'col-sm-' ~ col_sm[loop.index0],
+      col_md[loop.index0] ? 'col-md-' ~ col_md[loop.index0],
+      col_lg[loop.index0] ? 'col-lg-' ~ col_lg[loop.index0],
+      col_xl[loop.index0] ? 'col-xl-' ~ col_xl[loop.index0],
+      col_xxl[loop.index0] ? 'col-xxl-' ~ col_xxl[loop.index0],
+      col_offset[loop.index0] ? 'offset-' ~ col_offset[loop.index0],
+    ]) }}>
+      {{ region }}
+    </div>
+  {% endfor %}
+</div>
+
+{% if container %}
+  </div>
+  {% if container_wrapper_attributes.storage() %}
+  </div>
+  {% endif %}
+{% endif %}
diff --git a/components/grid_row_3/grid_row_3.component.yml b/components/grid_row_3/grid_row_3.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e0fadc2387ff34f8c26939726a07b8b5a6c11bfc
--- /dev/null
+++ b/components/grid_row_3/grid_row_3.component.yml
@@ -0,0 +1,293 @@
+name: "Grid Row 3 Cols (Bootstrap)"
+description: "The grid system uses a series of containers, rows, and columns to layout and align content. Use the container attributes, row attributes (= component attributes) and/or col attributes to set responsive declinations of classes and/or classes already declared by styles."
+group: Layout
+icon_map:
+  - [main, second, third]
+links:
+  - url: 'https://getbootstrap.com/docs/5.3/layout/containers/'
+    title: 'See container documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/grid/'
+    title: 'See grid documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/columns/'
+    title: 'See columns documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/gutters/'
+    title: 'See gutters documentation'
+slots:
+  col_1_content:
+    title: "Col 1"
+    description: "The content of the column 1."
+  col_2_content:
+    title: "Col 2"
+    description: "The content of the column 2."
+  col_3_content:
+    title: "Col 3"
+    description: "The content of the column 3."
+props:
+  type: object
+  properties:
+    container:
+      title: Container
+      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
+      type: string
+      enum:
+        - container
+        - container-sm
+        - container-md
+        - container-lg
+        - container-xl
+        - container-xxl
+        - container-fluid
+      "meta:enum":
+        container: Container
+        container-sm: "Container small"
+        container-md: "Container medium"
+        container-lg: "Container large"
+        container-xl: "Container x-large"
+        container-xxl: "Container xx-large"
+        container-fluid: "Container fluid"
+    container_attributes:
+      title: "Container attributes"
+      description: "The attributes to customize the tag with the container class if present."
+      $ref: "ui-patterns://attributes"
+    container_wrapper_attributes:
+      title: "Container wrapper attributes"
+      description: "The attributes to customize a div tag above the container class if present."
+      $ref: "ui-patterns://attributes"
+    gutters:
+      title: Gutters
+      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
+      type: string
+      enum:
+        - g-0
+        - g-1
+        - g-2
+        - g-3
+        - g-4
+        - g-5
+      "meta:enum":
+        g-0: "0"
+        g-1: "1"
+        g-2: "2"
+        g-3: "3"
+        g-4: "4"
+        g-5: "5"
+    gutters_horizontal:
+      title: "Horizontal gutters"
+      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
+      type: string
+      enum:
+        - gx-0
+        - gx-1
+        - gx-2
+        - gx-3
+        - gx-4
+        - gx-5
+      "meta:enum":
+        gx-0: "0"
+        gx-1: "1"
+        gx-2: "2"
+        gx-3: "3"
+        gx-4: "4"
+        gx-5: "5"
+    gutters_vertical:
+      title: "Vertical gutters"
+      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
+      type: string
+      enum:
+        - gy-0
+        - gy-1
+        - gy-2
+        - gy-3
+        - gy-4
+        - gy-5
+      "meta:enum":
+        gy-0: "0"
+        gy-1: "1"
+        gy-2: "2"
+        gy-3: "3"
+        gy-4: "4"
+        gy-5: "5"
+    row_cols:
+      title: "Row columns"
+      description: "Use theses classes to quickly set the number of columns that best render your content and layout. With 'Auto' you can give the columns their natural width."
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xs:
+      title: "All (Extra small)"
+      type: array
+      maxItems: 3
+      default: [12, 12, 12]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_sm:
+      title: Small
+      type: array
+      maxItems: 3
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_md:
+      title: Medium
+      type: array
+      maxItems: 3
+      default: [4, 4, 4]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_lg:
+      title: Large
+      type: array
+      maxItems: 3
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xl:
+      title: "Extra large"
+      type: array
+      maxItems: 3
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xxl:
+      title: "Extra extra large"
+      type: array
+      maxItems: 3
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_offset:
+      title: "Offset"
+      type: array
+      maxItems: 3
+      items:
+        type: integer
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+          - 6
+          - 7
+          - 8
+          - 9
+          - 10
+          - 11
+    col_1_attributes:
+      title: "Column 1 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_2_attributes:
+      title: "Column 2 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_3_attributes:
+      title: "Column 3 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
diff --git a/components/grid_row_3/grid_row_3.preview.story.yml b/components/grid_row_3/grid_row_3.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9cff69cdfb16f1e702705688514551c329d3fa2f
--- /dev/null
+++ b/components/grid_row_3/grid_row_3.preview.story.yml
@@ -0,0 +1,24 @@
+name: Preview
+slots:
+  col_1_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_2_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_3_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+props:
+  gutters: g-0
+  col_xs: [12, 12, 12]
+  col_md: [4, 4, 4]
diff --git a/components/grid_row_3/grid_row_3.twig b/components/grid_row_3/grid_row_3.twig
new file mode 100644
index 0000000000000000000000000000000000000000..72d4ea53a015aa94bdd01edb78a0839e54e5ddd6
--- /dev/null
+++ b/components/grid_row_3/grid_row_3.twig
@@ -0,0 +1,47 @@
+{% set container_wrapper_attributes = create_attribute(container_wrapper_attributes|default({})) %}
+{% set container_attributes = create_attribute(container_attributes|default({})) %}
+{% set col_attributes = [
+  create_attribute(col_1_attributes|default({})),
+  create_attribute(col_2_attributes|default({})),
+  create_attribute(col_3_attributes|default({})),
+] %}
+
+{% set attributes = attributes.addClass([
+  'row',
+  gutters,
+  gutters_horizontal,
+  gutters_vertical,
+  row_cols ? 'row-cols-' ~ row_cols,
+]) %}
+
+{% if container %}
+  {% if container_wrapper_attributes.storage() %}
+  <div{{ container_wrapper_attributes }}>
+  {% endif %}
+  <div{{ container_attributes.addClass(container) }}>
+{% endif %}
+
+<div{{ attributes }}>
+  {% for region in [col_1_content, col_2_content, col_3_content] %}
+    {% set region = region and region is not sequence ? [region] : region %}
+    <div{{ col_attributes[loop.index0].addClass([
+      'col',
+      col_xs[loop.index0] ? 'col-' ~ col_xs[loop.index0],
+      col_sm[loop.index0] ? 'col-sm-' ~ col_sm[loop.index0],
+      col_md[loop.index0] ? 'col-md-' ~ col_md[loop.index0],
+      col_lg[loop.index0] ? 'col-lg-' ~ col_lg[loop.index0],
+      col_xl[loop.index0] ? 'col-xl-' ~ col_xl[loop.index0],
+      col_xxl[loop.index0] ? 'col-xxl-' ~ col_xxl[loop.index0],
+      col_offset[loop.index0] ? 'offset-' ~ col_offset[loop.index0],
+    ]) }}>
+      {{ region }}
+    </div>
+  {% endfor %}
+</div>
+
+{% if container %}
+  </div>
+  {% if container_wrapper_attributes.storage() %}
+  </div>
+  {% endif %}
+{% endif %}
diff --git a/components/grid_row_4/grid_row_4.component.yml b/components/grid_row_4/grid_row_4.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0eedcc8f55075066c3ee71138d32c58db102ea00
--- /dev/null
+++ b/components/grid_row_4/grid_row_4.component.yml
@@ -0,0 +1,300 @@
+name: "Grid Row 4 Cols (Bootstrap)"
+description: "The grid system uses a series of containers, rows, and columns to layout and align content. Use the container attributes, row attributes (= component attributes) and/or col attributes to set responsive declinations of classes and/or classes already declared by styles."
+group: Layout
+icon_map:
+  - [main, second, third, fourth]
+links:
+  - url: 'https://getbootstrap.com/docs/5.3/layout/containers/'
+    title: 'See container documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/grid/'
+    title: 'See grid documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/columns/'
+    title: 'See columns documentation'
+  - url: 'https://getbootstrap.com/docs/5.3/layout/gutters/'
+    title: 'See gutters documentation'
+slots:
+  col_1_content:
+    title: "Col 1"
+    description: "The content of the column 1."
+  col_2_content:
+    title: "Col 2"
+    description: "The content of the column 2."
+  col_3_content:
+    title: "Col 3"
+    description: "The content of the column 3."
+  col_4_content:
+    title: "Col 4"
+    description: "The content of the column 4."
+props:
+  type: object
+  properties:
+    container:
+      title: Container
+      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
+      type: string
+      enum:
+        - container
+        - container-sm
+        - container-md
+        - container-lg
+        - container-xl
+        - container-xxl
+        - container-fluid
+      "meta:enum":
+        container: Container
+        container-sm: "Container small"
+        container-md: "Container medium"
+        container-lg: "Container large"
+        container-xl: "Container x-large"
+        container-xxl: "Container xx-large"
+        container-fluid: "Container fluid"
+    container_attributes:
+      title: "Container attributes"
+      description: "The attributes to customize the tag with the container class if present."
+      $ref: "ui-patterns://attributes"
+    container_wrapper_attributes:
+      title: "Container wrapper attributes"
+      description: "The attributes to customize a div tag above the container class if present."
+      $ref: "ui-patterns://attributes"
+    gutters:
+      title: Gutters
+      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
+      type: string
+      enum:
+        - g-0
+        - g-1
+        - g-2
+        - g-3
+        - g-4
+        - g-5
+      "meta:enum":
+        g-0: "0"
+        g-1: "1"
+        g-2: "2"
+        g-3: "3"
+        g-4: "4"
+        g-5: "5"
+    gutters_horizontal:
+      title: "Horizontal gutters"
+      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
+      type: string
+      enum:
+        - gx-0
+        - gx-1
+        - gx-2
+        - gx-3
+        - gx-4
+        - gx-5
+      "meta:enum":
+        gx-0: "0"
+        gx-1: "1"
+        gx-2: "2"
+        gx-3: "3"
+        gx-4: "4"
+        gx-5: "5"
+    gutters_vertical:
+      title: "Vertical gutters"
+      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
+      type: string
+      enum:
+        - gy-0
+        - gy-1
+        - gy-2
+        - gy-3
+        - gy-4
+        - gy-5
+      "meta:enum":
+        gy-0: "0"
+        gy-1: "1"
+        gy-2: "2"
+        gy-3: "3"
+        gy-4: "4"
+        gy-5: "5"
+    row_cols:
+      title: "Row columns"
+      description: "Use theses classes to quickly set the number of columns that best render your content and layout. With 'Auto' you can give the columns their natural width."
+      type: string
+      enum:
+        - "1"
+        - "2"
+        - "3"
+        - "4"
+        - "5"
+        - "6"
+        - "7"
+        - "8"
+        - "9"
+        - "10"
+        - "11"
+        - "12"
+        - "auto"
+      "meta:enum":
+        auto: "Auto"
+    col_xs:
+      title: "All (Extra small)"
+      type: array
+      maxItems: 4
+      default: [12, 12, 12, 12]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_sm:
+      title: Small
+      type: array
+      maxItems: 4
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_md:
+      title: Medium
+      type: array
+      maxItems: 4
+      default: [3, 3, 3, 3]
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_lg:
+      title: Large
+      type: array
+      maxItems: 4
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xl:
+      title: "Extra large"
+      type: array
+      maxItems: 4
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_xxl:
+      title: "Extra extra large"
+      type: array
+      maxItems: 4
+      items:
+        type: string
+        enum:
+          - "1"
+          - "2"
+          - "3"
+          - "4"
+          - "5"
+          - "6"
+          - "7"
+          - "8"
+          - "9"
+          - "10"
+          - "11"
+          - "12"
+          - "auto"
+        "meta:enum":
+          auto: "Auto"
+    col_offset:
+      title: "Offset"
+      type: array
+      maxItems: 4
+      items:
+        type: integer
+        enum:
+          - 1
+          - 2
+          - 3
+          - 4
+          - 5
+          - 6
+          - 7
+          - 8
+          - 9
+          - 10
+          - 11
+    col_1_attributes:
+      title: "Column 1 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_2_attributes:
+      title: "Column 2 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_3_attributes:
+      title: "Column 3 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
+    col_4_attributes:
+      title: "Column 4 attributes"
+      description: "The attributes to customize the tag with the col class."
+      $ref: "ui-patterns://attributes"
diff --git a/components/grid_row_4/grid_row_4.preview.story.yml b/components/grid_row_4/grid_row_4.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..54d4cbc3f57eb85888ce76d73238a1b669554ee2
--- /dev/null
+++ b/components/grid_row_4/grid_row_4.preview.story.yml
@@ -0,0 +1,30 @@
+name: Preview
+slots:
+  col_1_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_2_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_3_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+  col_4_content:
+    - type: component
+      component: "ui_suite_bootstrap:card"
+      story: preview
+      props:
+        variant: default
+props:
+  gutters: g-0
+  col_xs: [12, 12, 12, 12]
+  col_md: [3, 3, 3, 3]
diff --git a/components/grid_row_4/grid_row_4.twig b/components/grid_row_4/grid_row_4.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b23234e4c021a084ae96f930f90d06099c9f1bb0
--- /dev/null
+++ b/components/grid_row_4/grid_row_4.twig
@@ -0,0 +1,48 @@
+{% set container_wrapper_attributes = create_attribute(container_wrapper_attributes|default({})) %}
+{% set container_attributes = create_attribute(container_attributes|default({})) %}
+{% set col_attributes = [
+  create_attribute(col_1_attributes|default({})),
+  create_attribute(col_2_attributes|default({})),
+  create_attribute(col_3_attributes|default({})),
+  create_attribute(col_4_attributes|default({})),
+] %}
+
+{% set attributes = attributes.addClass([
+  'row',
+  gutters,
+  gutters_horizontal,
+  gutters_vertical,
+  row_cols ? 'row-cols-' ~ row_cols,
+]) %}
+
+{% if container %}
+  {% if container_wrapper_attributes.storage() %}
+  <div{{ container_wrapper_attributes }}>
+  {% endif %}
+  <div{{ container_attributes.addClass(container) }}>
+{% endif %}
+
+<div{{ attributes }}>
+  {% for region in [col_1_content, col_2_content, col_3_content, col_4_content] %}
+    {% set region = region and region is not sequence ? [region] : region %}
+    <div{{ col_attributes[loop.index0].addClass([
+      'col',
+      col_xs[loop.index0] ? 'col-' ~ col_xs[loop.index0],
+      col_sm[loop.index0] ? 'col-sm-' ~ col_sm[loop.index0],
+      col_md[loop.index0] ? 'col-md-' ~ col_md[loop.index0],
+      col_lg[loop.index0] ? 'col-lg-' ~ col_lg[loop.index0],
+      col_xl[loop.index0] ? 'col-xl-' ~ col_xl[loop.index0],
+      col_xxl[loop.index0] ? 'col-xxl-' ~ col_xxl[loop.index0],
+      col_offset[loop.index0] ? 'offset-' ~ col_offset[loop.index0],
+    ]) }}>
+      {{ region }}
+    </div>
+  {% endfor %}
+</div>
+
+{% if container %}
+  </div>
+  {% if container_wrapper_attributes.storage() %}
+  </div>
+  {% endif %}
+{% endif %}
diff --git a/components/list/list.component.yml b/components/list/list.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5c5e7577e65c02c35854c05022ca715be8825fcb
--- /dev/null
+++ b/components/list/list.component.yml
@@ -0,0 +1,29 @@
+name: List
+group: Typography
+links:
+  - "https://getbootstrap.com/docs/5.3/content/typography/#lists"
+variants:
+  default:
+    title: Default
+  unstyled:
+    title: Unstyled
+    description: "Remove the default list-style and left margin on list items (immediate children only). This only applies to immediate children list items, meaning you will need to add the class for any nested lists as well."
+  inline:
+    title: Inline
+    description: "Remove a list’s bullets and apply some light margin with a combination of two classes, .list-inline and .list-inline-item."
+slots:
+  items:
+    title: Items
+    description: "An array of render arrays."
+props:
+  type: object
+  properties:
+    list_type:
+      title: "List type"
+      type: string
+      enum:
+        - ul
+        - ol
+      "meta:enum":
+        ul: "ul (Default)"
+        ol: ol
diff --git a/components/list/list.preview.story.yml b/components/list/list.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9b78f6fd8bb2b31939be41fec98c9506c0a47708
--- /dev/null
+++ b/components/list/list.preview.story.yml
@@ -0,0 +1,14 @@
+name: Preview
+slots:
+  items:
+    - type: html_tag
+      tag: span
+      value: "Lorem ipsum"
+    - type: html_tag
+      tag: span
+      value: "Phasellus iaculis"
+    - type: html_tag
+      tag: span
+      value: "Nulla volutpat"
+props:
+  list_type: ul
diff --git a/templates/patterns/list/pattern-list.html.twig b/components/list/list.twig
similarity index 86%
rename from templates/patterns/list/pattern-list.html.twig
rename to components/list/list.twig
index c1f10b11cbe680ac71d4285fcecda919126e7b22..303d2a30c066988b9da749c183d14c168fca17c7 100644
--- a/templates/patterns/list/pattern-list.html.twig
+++ b/components/list/list.twig
@@ -3,6 +3,7 @@
 {% endif %}
 
 {% set list_type = list_type|default('ul') %}
+{% set items = items and items is not sequence ? [items] : items %}
 
 <{{ list_type }}{{ attributes }}>
   {% for item in items %}
diff --git a/components/list_group/list_group.component.yml b/components/list_group/list_group.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..aa7d37fc363e29ffdb4f5016cb5a0e972f4b7c86
--- /dev/null
+++ b/components/list_group/list_group.component.yml
@@ -0,0 +1,55 @@
+name: "List Group"
+description: "List groups are a flexible and powerful component for displaying a series of content. Modify and extend them to support just about any content within."
+group: "List group"
+links:
+  - "https://getbootstrap.com/docs/5.3/components/list-group/"
+variants:
+  default:
+    title: Default
+    description: "The most basic list group is an unordered list with list items and the proper classes. Build upon it with the options that follow, or with your own CSS as needed."
+  flush:
+    title: Flush
+    description: "Add .list-group-flush to remove some borders and rounded corners to render list group items edge-to-edge in a parent container (e.g., cards)."
+  numbered:
+    title: Numbered
+    description: "Add the .list-group-numbered modifier class (and optionally use an <ol> element) to opt into numbered list group items."
+  horizontal:
+    title: Horizontal
+    description: "Add .list-group-horizontal to change the layout of list group items from vertical to horizontal across all breakpoints. Currently horizontal list groups cannot be combined with flush list groups."
+  horizontal_sm:
+    title: "Horizontal Small"
+    description: "Horizontal starts at breakpoint small."
+  horizontal_md:
+    title: "Horizontal Medium"
+    description: "Horizontal starts at breakpoint medium."
+  horizontal_lg:
+    title: "Horizontal Large"
+    description: "Horizontal starts at breakpoint large."
+  horizontal_xl:
+    title: "Horizontal Extra large"
+    description: "Horizontal starts at breakpoint extra large."
+  horizontal_xxl:
+    title: "Horizontal Extra extra large"
+    description: "Horizontal starts at breakpoint extra extra large."
+  numbered__horizontal:
+    title: "Numbered Horizontal"
+    description: "Add the .list-group-numbered modifier class (and optionally use an <ol> element) to opt into numbered list group items. Add .list-group-horizontal to change the layout of list group items from vertical to horizontal across all breakpoints. Currently horizontal list groups cannot be combined with flush list groups."
+  numbered__horizontal_sm:
+    title: "Numbered Horizontal Small"
+    description: "Horizontal starts at breakpoint small."
+  numbered__horizontal_md:
+    title: "Numbered Horizontal Medium"
+    description: "Horizontal starts at breakpoint medium."
+  numbered__horizontal_lg:
+    title: "Numbered Horizontal Large"
+    description: "Horizontal starts at breakpoint large."
+  numbered__horizontal_xl:
+    title: "Numbered Horizontal Extra large"
+    description: "Horizontal starts at breakpoint extra large."
+  numbered__horizontal_xxl:
+    title: "Numbered Horizontal Extra extra large"
+    description: "Horizontal starts at breakpoint extra extra large."
+slots:
+  items:
+    title: Items
+    description: "A list of List Group Items patterns."
diff --git a/components/list_group/list_group.preview.story.yml b/components/list_group/list_group.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..73a94ba60282de8075e65d8f2ed2afdaf8db5e19
--- /dev/null
+++ b/components/list_group/list_group.preview.story.yml
@@ -0,0 +1,29 @@
+name: Preview
+slots:
+  items:
+    - type: component
+      component: "ui_suite_bootstrap:list_group_item"
+      slots:
+        content: "The current link item"
+      props:
+        active: true
+    - type: component
+      component: "ui_suite_bootstrap:list_group_item"
+      slots:
+        content: "A second link item"
+    - type: component
+      component: "ui_suite_bootstrap:list_group_item"
+      slots:
+        content: "A third link item"
+    - type: component
+      component: "ui_suite_bootstrap:list_group_item"
+      slots:
+        content: "A fourth link item, with a link"
+      props:
+        url: "https://example.com"
+    - type: component
+      component: "ui_suite_bootstrap:list_group_item"
+      slots:
+        content: "The disabled link item"
+      props:
+        disabled: true
diff --git a/templates/patterns/list_group/pattern-list-group.html.twig b/components/list_group/list_group.twig
similarity index 100%
rename from templates/patterns/list_group/pattern-list-group.html.twig
rename to components/list_group/list_group.twig
diff --git a/components/list_group_item/list_group_item.component.yml b/components/list_group_item/list_group_item.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4aaa506fc20a6dd624e615d556c63c30e9a47f8c
--- /dev/null
+++ b/components/list_group_item/list_group_item.component.yml
@@ -0,0 +1,43 @@
+name: "(List Group Item)"
+description: "Internal: to be used in the 'List Group' component."
+group: "List group"
+links:
+  - "https://getbootstrap.com/docs/5.3/components/list-group/"
+variants:
+  default:
+    title: Default
+  primary:
+    title: Primary
+  secondary:
+    title: Secondary
+  success:
+    title: Success
+  danger:
+    title: Danger
+  warning:
+    title: Warning
+  info:
+    title: Info
+  light:
+    title: Light
+  dark:
+    title: Dark
+slots:
+  content:
+    title: Content
+    description: "Plain text, or any kind of content."
+props:
+  type: object
+  properties:
+    active:
+      title: "Active?"
+      description: "Indicate the current active selection."
+      type: boolean
+    disabled:
+      title: "Disabled?"
+      description: "Make it appears disabled. Note that some elements with .disabled will also require custom JavaScript to fully disable their click events (e.g., links)."
+      type: boolean
+    url:
+      title: URL
+      description: "The button URL. Optional."
+      $ref: "ui-patterns://url"
diff --git a/components/list_group_item/list_group_item.preview.story.yml b/components/list_group_item/list_group_item.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5829e0c7dcd7bcdddaa5b96249e3e6153e32f393
--- /dev/null
+++ b/components/list_group_item/list_group_item.preview.story.yml
@@ -0,0 +1,6 @@
+name: Preview
+slots:
+  content: "An item"
+props:
+  active: false
+  disabled: false
diff --git a/templates/patterns/list_group_item/pattern-list-group-item.html.twig b/components/list_group_item/list_group_item.twig
similarity index 100%
rename from templates/patterns/list_group_item/pattern-list-group-item.html.twig
rename to components/list_group_item/list_group_item.twig
diff --git a/components/modal/modal.component.yml b/components/modal/modal.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1205e1a16946707aac4ba5002b707412e975e019
--- /dev/null
+++ b/components/modal/modal.component.yml
@@ -0,0 +1,83 @@
+name: Modal
+description: "Use Bootstrap's JavaScript modal plugin to add dialogs to your site for lightboxes, user notifications, or completely custom content."
+group: Dialog
+links:
+  - "https://getbootstrap.com/docs/5.3/components/modal/"
+variants:
+  sm:
+    title: Small
+  default:
+    title: Default
+  lg:
+    title: Large
+  xl:
+    title: "Extra large"
+slots:
+  title:
+    title: Title
+    description: "Modal title."
+  body:
+    title: Body
+    description: "The content of the modal."
+  footer:
+    title: "Footer content"
+    description: "Footer content"
+props:
+  type: object
+  properties:
+    animation:
+      title: Animation
+      description: "For modals that simply appear rather than fade in to view."
+      type: boolean
+    static:
+      title: "Static backdrop"
+      description: "When checked, the modal will not close when clicking outside of it."
+      type: boolean
+    centered:
+      title: "Vertically centered"
+      description: "Vertically center the modal."
+      type: boolean
+    scrollable:
+      title: Scrollable
+      description: "Allows to scroll the modal body."
+      type: boolean
+    fullscreen:
+      title: Fullscreen
+      description: "Pop up a modal that covers the user viewport."
+      type: string
+      enum:
+        - modal-fullscreen
+        - modal-fullscreen-sm-down
+        - modal-fullscreen-md-down
+        - modal-fullscreen-lg-down
+        - modal-fullscreen-xl-down
+        - modal-fullscreen-xxl-down
+      "meta:enum":
+        modal-fullscreen: Always
+        modal-fullscreen-sm-down: "Below small"
+        modal-fullscreen-md-down: "Below medium"
+        modal-fullscreen-lg-down: "Below large"
+        modal-fullscreen-xl-down: "Below extra large"
+        modal-fullscreen-xxl-down: "Below extra extra large"
+    heading_level:
+      title: "Heading level"
+      description: "Heading level of the modal."
+      type: integer
+      enum:
+        - 1
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        1: "h1 (Default)"
+        2: h2
+        3: h3
+        4: h4
+        5: h5
+        6: h6
+    modal_id:
+      title: ID
+      description: "ID used by external buttons to toggle the visibility. Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
diff --git a/components/modal/modal.preview.story.yml b/components/modal/modal.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..816152ad918734f67f0e61f68e60a857d3e643d3
--- /dev/null
+++ b/components/modal/modal.preview.story.yml
@@ -0,0 +1,37 @@
+name: Preview
+slots:
+  title: "Modal title"
+  body: "Modal body text goes here."
+  footer:
+    - type: component
+      attributes:
+        data-bs-dismiss: modal
+      component: "ui_suite_bootstrap:button"
+      slots:
+        label: Close
+      props:
+        variant: secondary__sm
+    - type: component
+      component: "ui_suite_bootstrap:button"
+      slots:
+        label: "Save changes"
+      props:
+        variant: primary__sm
+props:
+  animation: true
+  static: false
+  centered: false
+  scrollable: false
+  heading_level: 1
+library_wrapper: >
+  {% set modal_id = modal_id|default("modal-" ~ random()) %}
+  {% set props = {'#props': _story['#props']|merge({'modal_id': modal_id})} %}
+  {{ include('ui_suite_bootstrap:button', {
+    'label': 'Launch demo modal'|t,
+    'variant': 'primary',
+    'attributes': {
+      'data-bs-target': '#' ~ modal_id,
+      'data-bs-toggle':'modal',
+    },
+  }, with_context = false) }}
+  {{ _story|merge(props) }}
diff --git a/templates/patterns/modal/pattern-modal.html.twig b/components/modal/modal.twig
similarity index 91%
rename from templates/patterns/modal/pattern-modal.html.twig
rename to components/modal/modal.twig
index 7e1d6c03ec6388e673fabbb5f7a5b8e53167850b..267edabbe93548143265fc3df7c852bd575d73e3 100644
--- a/templates/patterns/modal/pattern-modal.html.twig
+++ b/components/modal/modal.twig
@@ -29,11 +29,11 @@
         {% if title %}
           <h{{ heading_level }} class="modal-title" id="label_{{ modal_id }}">{{ title }}</h{{ heading_level }}>
         {% endif %}
-        {{ pattern('close_button', {
-          attributes: create_attribute({
-            'data-bs-dismiss': 'modal'
-          })
-        }) }}
+        {{ include('ui_suite_bootstrap:close_button', {
+          attributes: {
+            'data-bs-dismiss': 'modal',
+          },
+        }, with_context = false) }}
       </div>
 
     {% if body %}
diff --git a/components/nav/nav.component.yml b/components/nav/nav.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6502cae1b5bb8350433ba3c0ef1af6e2ec105ec6
--- /dev/null
+++ b/components/nav/nav.component.yml
@@ -0,0 +1,55 @@
+name: Nav
+description: "The base .nav component is built with flexbox and provide a strong foundation for building all types of navigation components. It includes some style overrides (for working with lists), some link padding for larger hit areas, and basic disabled styling."
+group: "Navs and tabs"
+links:
+  - "https://getbootstrap.com/docs/5.3/components/navs-tabs/"
+variants:
+  default:
+    title: Default
+  tabs:
+    title: Tabs
+  tabs__fill:
+    title: Tabs
+  tabs__justified:
+    title: Tabs
+  pills:
+    title: Pills
+  pills__fill:
+    title: "Pills filled"
+  pills__justified:
+    title: "Pills filled with same width"
+  underline:
+    title: Underline
+slots:
+  tab_content:
+    title: "Tab content"
+    description: "A list of renderable elements. Each item will be put in tab panes and the nav items will be used to navigate among the panes. You need to ensure that there is the same amount of nav links and tab items."
+props:
+  type: object
+  properties:
+    nav_id:
+      title: "Nav ID"
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+    nav_type:
+      title: "List type"
+      type: string
+      enum:
+        - ul
+        - ol
+        - nav
+      "meta:enum":
+        ul: "ul (Default)"
+        ol: ol
+        nav: nav
+    dropdown_id:
+      title: "Dropdown ID"
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+    card_header:
+      title: "Card header"
+      description: "Styling adjustment for tabs and pills variants when used in the header of the card component."
+      type: boolean
+    items:
+      title: "Nav items"
+      $ref: "ui-patterns://links"
diff --git a/components/nav/nav.preview.story.yml b/components/nav/nav.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2867986e080f3ac8bfbe3a3ef0032b7a9b4b27f5
--- /dev/null
+++ b/components/nav/nav.preview.story.yml
@@ -0,0 +1,43 @@
+name: Preview
+props:
+  nav_type: ul
+  card_header: false
+  items:
+    - url: "#"
+      title: Active
+      link_attributes:
+        class:
+          - active
+    - title: Dropdown
+      url: "#"
+      below:
+        - title: "Dropdown header"
+          link_attributes:
+            class:
+              - dropdown-header
+        - title: Action
+          url: "#"
+        - title: "Dropdown item text"
+        - title: "Another action"
+          url: "#"
+        - title: "Something else here"
+          url: "#"
+        - {}
+        - title: "Separated link"
+          url: "#"
+        - title: "Action (button)"
+          link_attributes:
+            class:
+              - dropdown-item
+        - title: "Another action (button)"
+          link_attributes:
+            class:
+              - dropdown-item
+        - title: "Something else here (text)"
+    - url: "#"
+      title: "Much longer nav link"
+    - url: "#"
+      title: Disabled
+      link_attributes:
+        class:
+          - disabled
diff --git a/templates/patterns/nav/pattern-nav.html.twig b/components/nav/nav.twig
similarity index 93%
rename from templates/patterns/nav/pattern-nav.html.twig
rename to components/nav/nav.twig
index 006642a815ef472436039b124bfb6d0d02ff3b2b..8a1e30d7060a31e7cf8c09d0af159259db2bee13 100644
--- a/templates/patterns/nav/pattern-nav.html.twig
+++ b/components/nav/nav.twig
@@ -5,6 +5,7 @@
   {% set attributes = card_header and 'pills' in variant ? attributes.addClass('card-header-pills') : attributes %}
 {% endif %}
 
+{% set tab_content = tab_content and tab_content is not sequence ? [tab_content] : tab_content %}
 {% set nav_id = nav_id|default('nav-' ~ random()) %}
 {% set nav_type = nav_type|default('ul') %}
 {% set link_type = tab_content ? 'button' : 'a' %}
@@ -35,17 +36,17 @@
     {% endif %}
 
     {% if item.below %}
-      {{ pattern('dropdown', {
-        'variant': 'dropdown',
+      {{ include('ui_suite_bootstrap:dropdown', {
         'title': item.title,
+        'attributes': item_attributes,
+        'variant': 'dropdown',
+        'auto_close': 'true',
+        'button_attributes': link_attributes,
+        'button_variant': 'default',
         'content': item.below,
         'dropdown_id': dropdown_id|default("dropdown-" ~ random())  ~ "-" ~ loop.index0,
-        'auto_close': 'true',
         'dropdown_navbar': nav_type in ['ul', 'ol'],
-        'button_variant': 'default',
-        'button_attributes': link_attributes,
-        'attributes': item_attributes
-      }) }}
+      }, with_context = false) }}
     {% else %}
       <{{ link_type }}{{ link_attributes }}>
         {{ item.title }}
diff --git a/components/navbar/navbar.component.yml b/components/navbar/navbar.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9bb620d311dd15c1a3569e0835221e6d2a6ba02e
--- /dev/null
+++ b/components/navbar/navbar.component.yml
@@ -0,0 +1,93 @@
+name: Navbar
+description: "Powerful, responsive navigation header, the navbar. Includes support for branding, navigation, and more, including support for our collapse plugin."
+group: Navbar
+links:
+  - "https://getbootstrap.com/docs/5.3/components/navbar/"
+variants:
+  default:
+    title: Default
+  expand_sm:
+    title: "Expand small"
+  expand_md:
+    title: "Expand medium"
+  expand_lg:
+    title: "Expand large"
+  expand_xl:
+    title: "Expand extra large"
+  expand_xxl:
+    title: "Expand extra extra large"
+  dark:
+    title: "Dark (deprecated)"
+  dark__expand_sm:
+    title: "Dark expand small (deprecated)"
+  dark__expand_md:
+    title: "Dark expand medium (deprecated)"
+  dark__expand_lg:
+    title: "Dark expand large (deprecated)"
+  dark__expand_xl:
+    title: "Dark expand extra large (deprecated)"
+  dark__expand_xxl:
+    title: "Dark expand extra extra large (deprecated)"
+slots:
+  brand:
+    title: Brand
+  navigation:
+    title: Navigation
+    description: "Navigation elements (brand, text, etc.) displayed even on small screens."
+  navigation_collapsible:
+    title: "Navigation collapsible"
+    description: "Navigation elements (menu links, etc.) displayed on collapsible dropdown on small screens."
+  offcanvas_label:
+    title: "Offcanvas label"
+    description: "When using the offcanvas feature, used for labelling."
+props:
+  type: object
+  properties:
+    navbar_id:
+      title: ID
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+    placement:
+      title: Placement
+      type: string
+      enum:
+        - default
+        - fixed-top
+        - fixed-bottom
+        - sticky-top
+        - sticky-bottom
+      "meta:enum":
+        default: Default
+        fixed-top: "Fixed top"
+        fixed-bottom: "Fixed bottom"
+        sticky-top: "Sticky top"
+        sticky-bottom: "Sticky bottom"
+    toggler_position:
+      title: "Toggler position"
+      description: "Navbar togglers are left-aligned by default, but should they follow a sibling element like a .navbar-brand, they’ll automatically be aligned to the far right. Reversing your markup will reverse the placement of the toggler"
+      type: string
+      enum:
+        - start
+        - end
+      "meta:enum":
+        start: Start
+        end: End
+    toggle_action:
+      title: "Toggle action"
+      description: "Transform your expanding and collapsing navbar into an offcanvas drawer with the offcanvas plugin."
+      type: string
+      enum:
+        - collapse
+        - offcanvas
+      "meta:enum":
+        collapse: "Collapse (default)"
+        offcanvas: Offcanvas
+    offcanvas_position:
+      title: "Offcanvas position"
+      type: string
+      enum:
+        - start
+        - end
+      "meta:enum":
+        start: Start
+        end: "End (default)"
diff --git a/components/navbar/navbar.dark.story.yml b/components/navbar/navbar.dark.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..50ad1f4315c61051b3189bec3dabd8fcb272d5fb
--- /dev/null
+++ b/components/navbar/navbar.dark.story.yml
@@ -0,0 +1,37 @@
+name: Dark
+slots:
+  brand:
+    - theme: image
+      uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNDA4Ij48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYSIgeDE9Ijc2LjA3OSIgeDI9IjUyMy40OCIgeTE9IjEwLjc5OCIgeTI9IjM2NS45NDUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjOTAxM2ZlIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjYxMGYyIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYiIgeDE9IjE5My41MDgiIHgyPSIyOTMuNTE0IiB5MT0iMTA5Ljc0IiB5Mj0iMjc4Ljg3MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNmMWU1ZmMiLz48L2xpbmVhckdyYWRpZW50PjxmaWx0ZXIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBpZD0iYnMtbG9nby1jIiB3aWR0aD0iMTk3IiBoZWlnaHQ9IjI0OSIgeD0iMTYxLjkwMSIgeT0iODMuNDU3IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiLz48ZmVPZmZzZXQgZHk9IjQiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI4Ii8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjE1IDAiLz48ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWEpIiBkPSJNNTYuNDgxIDUzLjMyQzU1LjUxNSAyNS41OCA3Ny4xMjggMCAxMDYuMzQyIDBoMjk5LjM1M2MyOS4yMTQgMCA1MC44MjcgMjUuNTggNDkuODYxIDUzLjMyLS45MjggMjYuNjQ3LjI3NyA2MS4xNjUgOC45NjQgODkuMzEgOC43MTUgMjguMjMyIDIzLjQxMSA0Ni4wNzcgNDcuNDggNDguMzd2MjZjLTI0LjA2OSAyLjI5My0zOC43NjUgMjAuMTM4LTQ3LjQ4IDQ4LjM3LTguNjg3IDI4LjE0NS05Ljg5MiA2Mi42NjMtOC45NjQgODkuMzExLjk2NiAyNy43MzktMjAuNjQ3IDUzLjMxOS00OS44NjEgNTMuMzE5SDEwNi4zNDJjLTI5LjIxNCAwLTUwLjgyNy0yNS41OC00OS44Ni01My4zMTkuOTI3LTI2LjY0OC0uMjc4LTYxLjE2Ni04Ljk2Ni04OS4zMTFDMzguODAyIDIzNy4xMzggMjQuMDcgMjE5LjI5MyAwIDIxN3YtMjZjMjQuMDY5LTIuMjkzIDM4LjgwMi0yMC4xMzggNDcuNTE2LTQ4LjM3IDguNjg4LTI4LjE0NSA5Ljg5My02Mi42NjMgOC45NjUtODkuMzF6Ii8+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWIpIiBmaWx0ZXI9InVybCgjYnMtbG9nby1jKSIgc3Ryb2tlPSIjZmZmIiBkPSJNMjY3LjEwMyAzMTIuNDU3YzQ3LjI5NyAwIDc1Ljc5OC0yMy4xNTggNzUuNzk4LTYxLjM1NSAwLTI4Ljg3My0yMC4zMzYtNDkuNzc2LTUwLjUzMi01My4wODV2LTEuMjAzYzIyLjE4NS0zLjYwOSAzOS41OTQtMjQuMjExIDM5LjU5NC00Ny4yMTkgMC0zMi43ODMtMjUuODgyLTU0LjEzOC02NS4zMjItNTQuMTM4aC04OC43NHYyMTdoODkuMjAyem0tNTQuNjkyLTE4OS40OGg0NS45MTFjMjQuOTU4IDAgMzkuMTMxIDExLjEyOCAzOS4xMzEgMzEuMjc5IDAgMjEuNTA1LTE2LjQ4NCAzMy41MzUtNDYuMzcyIDMzLjUzNWgtMzguNjd2LTY0LjgxNHptMCAxNjEuOTYxdi03MS40MzFoNDUuNjAyYzMyLjY2MSAwIDQ5LjYwOCAxMi4wMyA0OS42MDggMzUuNDkgMCAyMy40NTktMTYuNDg0IDM1Ljk0MS00Ny42MDUgMzUuOTQxaC00Ny42MDV6Ii8+PC9zdmc+Cg=="
+      attributes:
+        width: 40px
+        height: 32px
+    - type: html_tag
+      tag: a
+      attributes:
+        href: "#"
+      value: Brand
+  navigation:
+    type: html_tag
+    tag: span
+    attributes:
+      class:
+        - navbar-text
+    value: Text
+  navigation_collapsible:
+    type: component
+    component: "ui_suite_bootstrap:navbar_nav"
+    story: preview
+    props:
+      variant: default
+  offcanvas_label: Offcanvas
+props:
+  attributes:
+    class:
+      - bg-dark
+    data-bs-theme: dark
+  variant: default
+  placement: default
+  toggler_position: end
+  toggle_action: collapse
+  offcanvas_position: end
diff --git a/components/navbar/navbar.preview.story.yml b/components/navbar/navbar.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6bfd9a916a6292a5da5cb27a3205f670617f364b
--- /dev/null
+++ b/components/navbar/navbar.preview.story.yml
@@ -0,0 +1,36 @@
+name: Preview
+slots:
+  brand:
+    - theme: image
+      uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNDA4Ij48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYSIgeDE9Ijc2LjA3OSIgeDI9IjUyMy40OCIgeTE9IjEwLjc5OCIgeTI9IjM2NS45NDUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjOTAxM2ZlIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjYxMGYyIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYiIgeDE9IjE5My41MDgiIHgyPSIyOTMuNTE0IiB5MT0iMTA5Ljc0IiB5Mj0iMjc4Ljg3MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNmMWU1ZmMiLz48L2xpbmVhckdyYWRpZW50PjxmaWx0ZXIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBpZD0iYnMtbG9nby1jIiB3aWR0aD0iMTk3IiBoZWlnaHQ9IjI0OSIgeD0iMTYxLjkwMSIgeT0iODMuNDU3IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiLz48ZmVPZmZzZXQgZHk9IjQiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI4Ii8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjE1IDAiLz48ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWEpIiBkPSJNNTYuNDgxIDUzLjMyQzU1LjUxNSAyNS41OCA3Ny4xMjggMCAxMDYuMzQyIDBoMjk5LjM1M2MyOS4yMTQgMCA1MC44MjcgMjUuNTggNDkuODYxIDUzLjMyLS45MjggMjYuNjQ3LjI3NyA2MS4xNjUgOC45NjQgODkuMzEgOC43MTUgMjguMjMyIDIzLjQxMSA0Ni4wNzcgNDcuNDggNDguMzd2MjZjLTI0LjA2OSAyLjI5My0zOC43NjUgMjAuMTM4LTQ3LjQ4IDQ4LjM3LTguNjg3IDI4LjE0NS05Ljg5MiA2Mi42NjMtOC45NjQgODkuMzExLjk2NiAyNy43MzktMjAuNjQ3IDUzLjMxOS00OS44NjEgNTMuMzE5SDEwNi4zNDJjLTI5LjIxNCAwLTUwLjgyNy0yNS41OC00OS44Ni01My4zMTkuOTI3LTI2LjY0OC0uMjc4LTYxLjE2Ni04Ljk2Ni04OS4zMTFDMzguODAyIDIzNy4xMzggMjQuMDcgMjE5LjI5MyAwIDIxN3YtMjZjMjQuMDY5LTIuMjkzIDM4LjgwMi0yMC4xMzggNDcuNTE2LTQ4LjM3IDguNjg4LTI4LjE0NSA5Ljg5My02Mi42NjMgOC45NjUtODkuMzF6Ii8+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWIpIiBmaWx0ZXI9InVybCgjYnMtbG9nby1jKSIgc3Ryb2tlPSIjZmZmIiBkPSJNMjY3LjEwMyAzMTIuNDU3YzQ3LjI5NyAwIDc1Ljc5OC0yMy4xNTggNzUuNzk4LTYxLjM1NSAwLTI4Ljg3My0yMC4zMzYtNDkuNzc2LTUwLjUzMi01My4wODV2LTEuMjAzYzIyLjE4NS0zLjYwOSAzOS41OTQtMjQuMjExIDM5LjU5NC00Ny4yMTkgMC0zMi43ODMtMjUuODgyLTU0LjEzOC02NS4zMjItNTQuMTM4aC04OC43NHYyMTdoODkuMjAyem0tNTQuNjkyLTE4OS40OGg0NS45MTFjMjQuOTU4IDAgMzkuMTMxIDExLjEyOCAzOS4xMzEgMzEuMjc5IDAgMjEuNTA1LTE2LjQ4NCAzMy41MzUtNDYuMzcyIDMzLjUzNWgtMzguNjd2LTY0LjgxNHptMCAxNjEuOTYxdi03MS40MzFoNDUuNjAyYzMyLjY2MSAwIDQ5LjYwOCAxMi4wMyA0OS42MDggMzUuNDkgMCAyMy40NTktMTYuNDg0IDM1Ljk0MS00Ny42MDUgMzUuOTQxaC00Ny42MDV6Ii8+PC9zdmc+Cg=="
+      attributes:
+        width: 40px
+        height: 32px
+    - type: html_tag
+      tag: a
+      attributes:
+        href: "#"
+      value: Brand
+  navigation:
+    type: html_tag
+    tag: span
+    attributes:
+      class:
+        - navbar-text
+    value: Text
+  navigation_collapsible:
+    type: component
+    component: "ui_suite_bootstrap:navbar_nav"
+    story: preview
+    props:
+      variant: default
+  offcanvas_label: Offcanvas
+props:
+  attributes:
+    class:
+      - bg-light
+  variant: default
+  placement: default
+  toggler_position: end
+  toggle_action: collapse
+  offcanvas_position: end
diff --git a/templates/patterns/navbar/pattern-navbar.html.twig b/components/navbar/navbar.twig
similarity index 95%
rename from templates/patterns/navbar/pattern-navbar.html.twig
rename to components/navbar/navbar.twig
index 7916599ad4508e8a9e71ae18af6c36c0f7fc4a29..81012fcf5e33ec4c8c6209c6c3c768e742f0fc39 100644
--- a/templates/patterns/navbar/pattern-navbar.html.twig
+++ b/components/navbar/navbar.twig
@@ -38,12 +38,12 @@
 
     {% if navigation_collapsible %}
       {% if toggle_action == 'offcanvas' %}
-        {{ pattern('offcanvas', {
-          'variant': offcanvas_position,
-          'offcanvas_id': navbar_id,
+        {{ include('ui_suite_bootstrap:offcanvas', {
           'title': offcanvas_label|default('Navigation'|t),
           'body': navigation_collapsible,
-        }) }}
+          'variant': offcanvas_position,
+          'offcanvas_id': navbar_id,
+        }, with_context = false) }}
       {% else %}
         <div class="collapse navbar-collapse" id="{{ navbar_id }}">
           {{ navigation_collapsible }}
diff --git a/components/navbar_nav/navbar_nav.component.yml b/components/navbar_nav/navbar_nav.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b54e2969d870bf696cb880c53cbc322482bdc55d
--- /dev/null
+++ b/components/navbar_nav/navbar_nav.component.yml
@@ -0,0 +1,21 @@
+name: "(Navbar nav)"
+description: "Internal: to be used in the 'Navbar' component."
+group: Navbar
+links:
+  - "https://getbootstrap.com/docs/5.3/components/navbar/"
+variants:
+  default:
+    title: Default
+  scroll:
+    title: Scroll
+props:
+  type: object
+  properties:
+    dropdown_id:
+      title: ID
+      description: "Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
+    items:
+      title: "Menu items"
+      description: "Full-height and lightweight navigation (including support for dropdowns)."
+      $ref: "ui-patterns://links"
diff --git a/components/navbar_nav/navbar_nav.preview.story.yml b/components/navbar_nav/navbar_nav.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..61f6748778901d5c69a1291749b730565b8f3d19
--- /dev/null
+++ b/components/navbar_nav/navbar_nav.preview.story.yml
@@ -0,0 +1,19 @@
+name: Preview
+props:
+  items:
+    - title: Home
+      url: "https://example.com"
+    - title: Library
+      url: "https://example.com"
+      below:
+        - title: "Dropdown header"
+          link_attributes:
+            class:
+              - dropdown-header
+        - title: "Sub 1"
+          url: "https://example.com"
+        - {}
+        - title: "Sub 2 after divider"
+          url: "https://example.com"
+        - title: "Dropdown text"
+    - title: Data
diff --git a/templates/patterns/navbar_nav/pattern-navbar-nav.html.twig b/components/navbar_nav/navbar_nav.twig
similarity index 89%
rename from templates/patterns/navbar_nav/pattern-navbar-nav.html.twig
rename to components/navbar_nav/navbar_nav.twig
index 69bbb55edcbd3b785b38923dd56477582cab44b4..cd73e2dc15efa020fbb3a58322470e7bd909f569 100644
--- a/templates/patterns/navbar_nav/pattern-navbar-nav.html.twig
+++ b/components/navbar_nav/navbar_nav.twig
@@ -27,18 +27,18 @@
     {% set item_attributes = create_attribute(item.attributes|default({})) %}
     {% set link_attributes = create_attribute(item.link_attributes|default({})) %}
     {% if item.below %}
-      {{ pattern('dropdown', {
-        'variant': 'dropdown',
+      {{ include('ui_suite_bootstrap:dropdown', {
         'title': item.title,
+        'attributes': {
+          'class': ['nav-item'],
+        },
+        'variant': 'dropdown',
+        'auto_close': 'true',
+        'button_attributes': link_attributes,
         'content': item.below,
         'dropdown_id': dropdown_id|default("dropdown-" ~ random())  ~ "-" ~ loop.index,
-        'auto_close': 'true',
         'dropdown_navbar': true,
-        'attributes': create_attribute({
-          'class': ['nav-item']
-        }),
-        'button_attributes': link_attributes
-      }) }}
+      }, with_context = false) }}
     {% elseif item.url %}
       <li{{ item_attributes.addClass('nav-item') }}>
         <a{{ link_attributes.setAttribute('href', item.url).addClass('nav-link') }}>{{ item.title }}</a>
diff --git a/components/offcanvas/offcanvas.component.yml b/components/offcanvas/offcanvas.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..84dd64a6d642371442657df3a7be563a26f1c3fd
--- /dev/null
+++ b/components/offcanvas/offcanvas.component.yml
@@ -0,0 +1,76 @@
+name: Offcanvas
+description: "Build hidden sidebars into your project for navigation, shopping carts, and more with a few classes and our JavaScript plugin."
+group: Dialog
+links:
+  - "https://getbootstrap.com/docs/5.3/components/offcanvas/"
+variants:
+  start:
+    title: Start
+  end:
+    title: End
+  top:
+    title: Top
+  bottom:
+    title: Bottom
+slots:
+  title:
+    title: Title
+    description: "Offcanvas title."
+  body:
+    title: Body
+    description: "The content of the offcanvas."
+props:
+  type: object
+  properties:
+    responsive:
+      title: Responsive
+      description: "Hide content in offcanvas below the selected breakpoint. Above that breakpoint, the contents within will behave as usual."
+      type: string
+      enum:
+        - offcanvas-sm
+        - offcanvas-md
+        - offcanvas-lg
+        - offcanvas-xl
+        - offcanvas-xxl
+      "meta:enum":
+        offcanvas-sm: "Hide below small"
+        offcanvas-md: "Hide below medium"
+        offcanvas-lg: "Hide below large"
+        offcanvas-xl: "Hide below extra large"
+        offcanvas-xxl: "Hide below extra extra large"
+    backdrop:
+      title: Backdrop
+      description: "When backdrop is set to static, the offcanvas will not close when clicking outside of it."
+      type: string
+      enum:
+        - "false"
+        - static
+      "meta:enum":
+        "false": "No backdrop"
+        static: Static
+    scroll:
+      title: "Body scrolling"
+      description: "By default, body scrolling is disabled."
+      type: boolean
+    heading_level:
+      title: "Heading level"
+      description: "Heading level of the offcanvas."
+      type: integer
+      enum:
+        - 1
+        - 2
+        - 3
+        - 4
+        - 5
+        - 6
+      "meta:enum":
+        1: h1
+        2: h2
+        3: h3
+        4: h4
+        5: "h5 (Default)"
+        6: h6
+    offcanvas_id:
+      title: ID
+      description: "ID used by external buttons to toggle the visibility. Must start with a letter. Randomly generated if empty."
+      $ref: "ui-patterns://identifier"
diff --git a/components/offcanvas/offcanvas.preview.story.yml b/components/offcanvas/offcanvas.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bbe07673d26455295d3af1769e179aa079377f24
--- /dev/null
+++ b/components/offcanvas/offcanvas.preview.story.yml
@@ -0,0 +1,21 @@
+name: Preview
+slots:
+  title: Offcanvas
+  body: "Content for the offcanvas goes here. You can place just about any Bootstrap component or custom elements here."
+props:
+  scroll: false
+  heading_level: 5
+library_wrapper: >
+  {% set offcanvas_id = offcanvas_id|default("offcanvas-" ~ random()) %}
+  {% set props = {'#props': _story['#props']|merge({'offcanvas_id': offcanvas_id})} %}
+  {{ include('ui_suite_bootstrap:button', {
+    'label': 'Launch offcanvas'|t,
+    'variant': 'primary',
+    'attributes': {
+      'data-bs-target': '#' ~ offcanvas_id,
+      'data-bs-toggle': 'offcanvas',
+      'aria-controls': offcanvas_id,
+      'aria-expanded': 'false',
+    },
+  }, with_context = false) }}
+  {{ _story|merge(props) }}
diff --git a/templates/patterns/offcanvas/pattern-offcanvas.html.twig b/components/offcanvas/offcanvas.twig
similarity index 87%
rename from templates/patterns/offcanvas/pattern-offcanvas.html.twig
rename to components/offcanvas/offcanvas.twig
index 63287aa3eee9fb9c7e688b158734b12a85368efe..f98aa66abf7274c7307f74f05998c98cb98dcd2a 100644
--- a/templates/patterns/offcanvas/pattern-offcanvas.html.twig
+++ b/components/offcanvas/offcanvas.twig
@@ -19,12 +19,12 @@
     {% if title %}
       <h{{ heading_level }} class="offcanvas-title" id="label_{{ offcanvas_id }}">{{ title }}</h{{ heading_level }}>
     {% endif %}
-    {{ pattern('close_button', {
-      attributes: create_attribute({
+    {{ include('ui_suite_bootstrap:close_button', {
+      attributes: {
         'data-bs-dismiss': 'offcanvas',
-        'data-bs-target': '#' ~ offcanvas_id
-      })
-    }) }}
+        'data-bs-target': '#' ~ offcanvas_id,
+      },
+    }, with_context = false) }}
   </div>
 
   {% if body %}
diff --git a/components/pagination/pagination.component.yml b/components/pagination/pagination.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..17e9a360b4cd18bfe950fd8e352f68e05eb1604f
--- /dev/null
+++ b/components/pagination/pagination.component.yml
@@ -0,0 +1,18 @@
+name: Pagination
+description: "Indicate a series of related content exists across multiple pages."
+group: Navigation
+links:
+  - "https://getbootstrap.com/docs/5.3/components/pagination/"
+variants:
+  sm:
+    title: Smaller
+  default:
+    title: Default
+  lg:
+    title: Larger
+props:
+  type: object
+  properties:
+    items:
+      title: "Pagination items"
+      $ref: "ui-patterns://links"
diff --git a/components/pagination/pagination.preview.story.yml b/components/pagination/pagination.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0db3081718c9f9f0cc149240cebbd0af7f354a34
--- /dev/null
+++ b/components/pagination/pagination.preview.story.yml
@@ -0,0 +1,16 @@
+name: Preview
+props:
+  items:
+    - url: "#"
+      title: "« First"
+    - url: "#"
+      title: "‹ Previous"
+    - title: "4"
+    - url: "#"
+      title: "5"
+    - url: "#"
+      title: "6"
+    - url: "#"
+      title: "Next ›"
+    - url: "#"
+      title: "Last »"
diff --git a/templates/patterns/pagination/pattern-pagination.html.twig b/components/pagination/pagination.twig
similarity index 100%
rename from templates/patterns/pagination/pattern-pagination.html.twig
rename to components/pagination/pagination.twig
diff --git a/components/progress/progress.component.yml b/components/progress/progress.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2e06cd8c033cfd839397cba27797ead50482073e
--- /dev/null
+++ b/components/progress/progress.component.yml
@@ -0,0 +1,43 @@
+name: Progress
+description: "The progress element displays an indicator showing the completion progress of a task, typically in the form of a bar. Progress components are built with two HTML elements, some CSS to set the width, and a few attributes. Bootstrap does not use the HTML5 <progress> element, ensuring you can stack progress bars, animate them, and place text labels over them."
+group: Progress
+links:
+  - "https://getbootstrap.com/docs/5.3/components/progress/"
+variants:
+  default:
+    title: Default
+  striped:
+    title: Striped
+  striped__animated:
+    title: "Animated stripes"
+slots:
+  label:
+    title: Label
+    description: "Text shown inside the progress bar."
+props:
+  type: object
+  properties:
+    aria_label:
+      title: "Aria label"
+      description: "Name of the progress bar for assistive technology."
+      type: string
+    percent:
+      title: "Total progress (%)"
+      description: "Width of the progress element representing total progress (25%, 50%, etc.)."
+      type: number
+    min:
+      title: "Minimum value"
+      description: "Minimum value of the progress element (default is 0). Used for an aria attribute."
+      type: number
+    max:
+      title: "Maximum value"
+      description: "Maximum value of the progress element (default is 100). Used for an aria attribute."
+      type: number
+    bar_height:
+      title: Height
+      description: "Height of progress element in pixels (px). Leave empty for default height."
+      type: number
+    stacked:
+      title: Stacked
+      description: "If the progress is stacked with others."
+      type: boolean
diff --git a/components/progress/progress.preview.story.yml b/components/progress/progress.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ec0b55773adad213a96023db70b838cdc325a852
--- /dev/null
+++ b/components/progress/progress.preview.story.yml
@@ -0,0 +1,8 @@
+name: Preview
+slots:
+  label: Label
+props:
+  percent: 50
+  min: 0
+  max: 100
+  stacked: false
diff --git a/templates/patterns/progress/pattern-progress.html.twig b/components/progress/progress.twig
similarity index 100%
rename from templates/patterns/progress/pattern-progress.html.twig
rename to components/progress/progress.twig
diff --git a/components/progress_stacked/progress_stacked.component.yml b/components/progress_stacked/progress_stacked.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3323dbace6ef70c9bf6694b1e0dbeb33fbc4a70e
--- /dev/null
+++ b/components/progress_stacked/progress_stacked.component.yml
@@ -0,0 +1,9 @@
+name: "Progress stacked"
+description: "You can include multiple progress components inside a container with .progress-stacked to create a single stacked progress bar. Note that in this case, the styling to set the visual width of the progress bar must be applied to the .progress elements, rather than the .progress-bars."
+group: Progress
+links:
+  - "https://getbootstrap.com/docs/5.3/components/progress/#multiple-bars"
+slots:
+  items:
+    title: "Progress bars"
+    description: "The progress bars to stack."
diff --git a/components/progress_stacked/progress_stacked.preview.story.yml b/components/progress_stacked/progress_stacked.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3ba5a8c9d075c1c7d779f136fc40d912f5d831b2
--- /dev/null
+++ b/components/progress_stacked/progress_stacked.preview.story.yml
@@ -0,0 +1,33 @@
+name: Preview
+slots:
+  items:
+    - type: component
+      component: "ui_suite_bootstrap:progress"
+      props:
+        aria_label: "Segment one"
+        percent: 15
+        min: 0
+        max: 100
+        stacked: true
+    - type: component
+      attributes:
+        class:
+          - bg-success
+      component: "ui_suite_bootstrap:progress"
+      props:
+        aria_label: "Segment two"
+        percent: 30
+        min: 0
+        max: 100
+        stacked: true
+    - type: component
+      attributes:
+        class:
+          - bg-info
+      component: "ui_suite_bootstrap:progress"
+      props:
+        aria_label: "Segment three"
+        percent: 20
+        min: 0
+        max: 100
+        stacked: true
diff --git a/templates/patterns/progress_stacked/pattern-progress-stacked.html.twig b/components/progress_stacked/progress_stacked.twig
similarity index 100%
rename from templates/patterns/progress_stacked/pattern-progress-stacked.html.twig
rename to components/progress_stacked/progress_stacked.twig
diff --git a/components/spinner/spinner.component.yml b/components/spinner/spinner.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..45a70710e6d68edcfe9bf0c8f744dce1fe7dd22b
--- /dev/null
+++ b/components/spinner/spinner.component.yml
@@ -0,0 +1,24 @@
+name: Spinner
+description: "Indicate the loading state of a component or page with Bootstrap spinners, built entirely with HTML, CSS, and no JavaScript."
+links:
+  - "https://getbootstrap.com/docs/5.3/components/spinners"
+variants:
+  border__border_sm:
+    title: "Border small"
+  border:
+    title: Border
+  grow__grow_sm:
+    title: "Growing small"
+  grow:
+    title: Growing
+props:
+  type: object
+  properties:
+    aria_hidden:
+      title: "Aria hidden"
+      description: "Hide the spinner for assistive technology. When a label is also present outside of the spinner."
+      type: boolean
+    visually_hidden_label:
+      title: "Visually hidden label"
+      description: "A visually hidden label if the spinner is used as standalone."
+      type: string
diff --git a/components/spinner/spinner.preview.story.yml b/components/spinner/spinner.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1e0bacf50813c6a42cfb003420f77bca08b3b8ab
--- /dev/null
+++ b/components/spinner/spinner.preview.story.yml
@@ -0,0 +1,4 @@
+name: Preview
+props:
+  aria_hidden: false
+  visually_hidden_label: Loading...
diff --git a/templates/patterns/spinner/pattern-spinner.html.twig b/components/spinner/spinner.twig
similarity index 100%
rename from templates/patterns/spinner/pattern-spinner.html.twig
rename to components/spinner/spinner.twig
diff --git a/components/table/table.component.yml b/components/table/table.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5cc9d617db2ad217baea71b0d4da64a1ee6da230
--- /dev/null
+++ b/components/table/table.component.yml
@@ -0,0 +1,172 @@
+name: Table
+description: "Due to the widespread use of <table> elements across third-party widgets like calendars and date pickers, Bootstrap’s tables are opt-in. Add the base class .table to any <table>, then extend with our optional modifier classes or custom styles. All table styles are not inherited in Bootstrap, meaning any nested tables can be styled independent from the parent."
+group: Table
+links:
+  - "https://getbootstrap.com/docs/5.3/content/tables/"
+variants:
+  default:
+    title: Default
+  sm:
+    title: Small
+  primary:
+    title: Primary
+  secondary:
+    title: Secondary
+  success:
+    title: Success
+  danger:
+    title: Danger
+  warning:
+    title: Warning
+  info:
+    title: Info
+  light:
+    title: Light
+  dark:
+    title: Dark
+  primary__sm:
+    title: "Primary small"
+  secondary__sm:
+    title: "Secondary small"
+  success__sm:
+    title: "Success small"
+  danger__sm:
+    title: "Danger small"
+  warning__sm:
+    title: "Warning small"
+  info__sm:
+    title: "Info small"
+  light__sm:
+    title: "Light small"
+  dark__sm:
+    title: "Dark small"
+slots:
+  colgroups:
+    title: Colgroups
+    description: "Sticked to Drupal structure after preprocessing of the Drupal table element."
+  header:
+    title: Header
+    description: "A sequence of cell components."
+  rows:
+    title: Rows
+    description: "A sequence of row components."
+  footer:
+    title: Footer
+    description: "A sequence of row components."
+  empty:
+    title: Empty
+    description: "Render element used when there is no rows."
+  caption:
+    title: Caption
+    description: "A caption functions like a heading for a table. It helps users with screen readers to find a table and understand what it's about and decide if they want to read it. By default it is displayed at the bottom of the table."
+props:
+  type: object
+  properties:
+    header_color:
+      title: "Table header color"
+      type: string
+      enum:
+        - primary
+        - secondary
+        - success
+        - danger
+        - warning
+        - info
+        - light
+        - dark
+      "meta:enum":
+        primary: Primary
+        secondary: Secondary
+        success: Success
+        danger: Danger
+        warning: Warning
+        info: Info
+        light: Light
+        dark: Dark
+    footer_color:
+      title: "Table footer color"
+      type: string
+      enum:
+        - primary
+        - secondary
+        - success
+        - danger
+        - warning
+        - info
+        - light
+        - dark
+      "meta:enum":
+        primary: Primary
+        secondary: Secondary
+        success: Success
+        danger: Danger
+        warning: Warning
+        info: Info
+        light: light
+        dark: Dark
+    stripes:
+      title: "Striped table"
+      description: "Add zebra-striping to either the rows and/or the columns of the table."
+      type: array
+      items:
+        type: string
+        enum:
+          - striped
+          - striped-columns
+        "meta:enum":
+          striped: "Striped rows"
+          striped-columns: "Striped columns"
+    borders:
+      title: "Table border style"
+      description: "By default, rows have borders, but not the table itself or the columns. The 'borders' option adds borders on all sides of the table and cells. 'Borderless' removes all borders."
+      type: string
+      enum:
+        - bordered
+        - borderless
+      "meta:enum":
+        bordered: "With borders"
+        borderless: Borderless
+    hover:
+      title: "Hoverable rows"
+      description: "Enable a hover state when passing the mouse over a row."
+      type: boolean
+    divider:
+      title: "Table group divider"
+      description: "Add a thicker, darker border between table groups."
+      type: array
+      items:
+        type: string
+        enum:
+          - thead
+          - tbody
+          - tfoot
+        "meta:enum":
+          thead: Header
+          tbody: Body
+          tfoot: Footer
+    responsive:
+      title: Responsive
+      description: "Responsive tables allow tables to be scrolled horizontally with ease."
+      type: string
+      enum:
+        - responsive
+        - responsive-sm
+        - responsive-md
+        - responsive-lg
+        - responsive-xl
+        - responsive-xxl
+      "meta:enum":
+        responsive: "Always responsive"
+        responsive-sm: "Responsive below small"
+        responsive-md: "Responsive below medium"
+        responsive-lg: "Responsive below large"
+        responsive-xl: "Responsive below extra large"
+        responsive-xxl: "Responsive below extra extra large"
+    caption_top:
+      title: "Caption top"
+      description: "Display caption at top of the table."
+      type: boolean
+    header_columns:
+      title: "Number of columns in the header"
+      description: "Used to display properly the empty message if the table is empty. Leave empty for automatic value."
+      type: number
diff --git a/components/table/table.preview.story.yml b/components/table/table.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..12b929b060167475148d50ce90b409e4d78715d9
--- /dev/null
+++ b/components/table/table.preview.story.yml
@@ -0,0 +1,959 @@
+name: Preview
+slots:
+  header:
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head (active)"
+      props:
+        tag: th
+        active: true
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+    - type: component
+      component: "ui_suite_bootstrap:table_cell"
+      slots:
+        content: "Table head"
+      props:
+        tag: th
+  rows:
+    - type: component
+      component: "ui_suite_bootstrap:table_row"
+      slots:
+        cells:
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 1"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 2"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 3"
+            props:
+              active: true
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 4"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 5"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 6"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 7"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 8"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 9"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 10"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 11"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 12"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 13"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 14"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 15"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 16"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 17"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 18"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 19"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 20"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 21"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 22"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 23"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 24"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 25"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 26"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 27"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 28"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 29"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 30"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 31"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 32"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 33"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 34"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 35"
+      props:
+        color: success
+    - type: component
+      component: "ui_suite_bootstrap:table_row"
+      slots:
+        cells:
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 1"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 2"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 3"
+            props:
+              active: true
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 4"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 5"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 6"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 7"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 8"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 9"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 10"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 11"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 12"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 13"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 14"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 15"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 16"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 17"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 18"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 19"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 20"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 21"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 22"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 23"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 24"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 25"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 26"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 27"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 28"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 29"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 30"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 31"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 32"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 33"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 34"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 35"
+      props:
+        color: warning
+    - type: component
+      component: "ui_suite_bootstrap:table_row"
+      slots:
+        cells:
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 1"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 2"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 3"
+            props:
+              active: true
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 4"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 5"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 6"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 7"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 8"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 9"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 10"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 11"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 12"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 13"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 14"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 15"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 16"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 17"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 18"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 19"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 20"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 21"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 22"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 23"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 24"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 25"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 26"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 27"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 28"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 29"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 30"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 31"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 32"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 33"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 34"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 35"
+    - type: component
+      component: "ui_suite_bootstrap:table_row"
+      slots:
+        cells:
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 1"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 2"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 3"
+            props:
+              active: true
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 4"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 5"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 6"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 7"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 8"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 9"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 10"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 11"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 12"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 13"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 14"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 15"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 16"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 17"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 18"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 19"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 20"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 21"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 22"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 23"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 24"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 25"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 26"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 27"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 28"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 29"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 30"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 31"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 32"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 33"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 34"
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: "Cell 35"
+  footer:
+    - type: component
+      component: "ui_suite_bootstrap:table_row"
+      slots:
+        cells:
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+            props:
+              active: true
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+          - type: component
+            component: "ui_suite_bootstrap:table_cell"
+            slots:
+              content: Footer
+  caption: "Example table (caption)"
+props:
+  header_color: light
+  stripes:
+    - striped
+  hover: true
+  divider:
+    - tbody
+  responsive: responsive
diff --git a/templates/patterns/table/pattern-table.html.twig b/components/table/table.twig
similarity index 82%
rename from templates/patterns/table/pattern-table.html.twig
rename to components/table/table.twig
index 0aa54eec04ae337fc3c4f158cd9d6c15c3b11392..1d4ea33cd81e4b28785d2b4a3c6f1b7a6e597e69 100644
--- a/templates/patterns/table/pattern-table.html.twig
+++ b/components/table/table.twig
@@ -18,6 +18,7 @@
 {% set attributes = borders ? attributes.addClass('table-' ~ borders|lower|replace({'_': '-'})) : attributes %}
 {% set attributes = hover ? attributes.addClass('table-hover') : attributes %}
 {% set attributes = caption_top ? attributes.addClass('caption-top') : attributes %}
+{% set colgroups = colgroups and colgroups is not sequence ? [colgroups] : colgroups %}
 
 {% if header_color %}
   {% set thead_attributes = thead_attributes.addClass('table-' ~ header_color|lower|replace({'_': '-'})) %}
@@ -58,8 +59,9 @@
 
   {% for colgroup in colgroups %}
     {% if colgroup.cols %}
+      {% set colgroup_cols = colgroup.cols is sequence ? colgroup.cols : [colgroup.cols] %}
       <colgroup{{ colgroup.attributes }}>
-        {% for col in colgroup.cols %}
+        {% for col in colgroup_cols %}
           <col{{ col.attributes }} />
         {% endfor %}
       </colgroup>
@@ -70,9 +72,9 @@
 
   {% if header %}
     <thead{{ thead_attributes }}>
-      {{ pattern('table_row', {
-        'cells': header
-      }) }}
+      {{ include('ui_suite_bootstrap:table_row', {
+        'cells': header,
+      }, with_context = false) }}
     </thead>
   {% endif %}
 
@@ -82,14 +84,14 @@
     </tbody>
   {% elseif empty %}
     <tbody{{ tbody_attributes }}>
-      {{ pattern('table_row', {
-        'cells': pattern('table_cell', {
-          'attributes': create_attribute({
+      {{ include('ui_suite_bootstrap:table_row', {
+        'cells': include('ui_suite_bootstrap:table_cell', {
+          'content': empty,
+          'attributes': {
             'colspan': header_columns,
-          }),
-          'content': empty
-        })
-      }) }}
+          },
+        }, with_context = false),
+      }, with_context = false) }}
     </tbody>
   {% endif %}
 
diff --git a/components/table_cell/table_cell.component.yml b/components/table_cell/table_cell.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5986c7874099df67d08a10ce2cb7d5d5d44c2815
--- /dev/null
+++ b/components/table_cell/table_cell.component.yml
@@ -0,0 +1,46 @@
+name: "(Table Cell)"
+description: "Internal: to be used in the 'Table' and 'Table Row' components."
+group: Table
+links:
+  - "https://getbootstrap.com/docs/5.3/content/tables/"
+slots:
+  content:
+    title: "Cell content"
+    description: "The cell content."
+props:
+  type: object
+  properties:
+    tag:
+      title: "HTML tag"
+      type: string
+      enum:
+        - th
+        - td
+      "meta:enum":
+        th: Head
+        td: "Data (default)"
+    color:
+      title: "Cell color"
+      type: string
+      enum:
+        - primary
+        - secondary
+        - success
+        - danger
+        - warning
+        - info
+        - light
+        - dark
+      "meta:enum":
+        primary: Primary
+        secondary: Secondary
+        success: Success
+        danger: Danger
+        warning: Warning
+        info: Info
+        light: Light
+        dark: Dark
+    active:
+      title: Active
+      description: "Active state"
+      type: boolean
diff --git a/components/table_cell/table_cell.preview.story.yml b/components/table_cell/table_cell.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3df7d74e0207d8fed7e16de5af781d4f38dfafe
--- /dev/null
+++ b/components/table_cell/table_cell.preview.story.yml
@@ -0,0 +1,6 @@
+name: Preview
+slots:
+  content: "Cell content"
+props:
+  tag: td
+  active: false
diff --git a/templates/patterns/table_cell/pattern-table-cell.html.twig b/components/table_cell/table_cell.twig
similarity index 100%
rename from templates/patterns/table_cell/pattern-table-cell.html.twig
rename to components/table_cell/table_cell.twig
diff --git a/components/table_row/table_row.component.yml b/components/table_row/table_row.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8bd5c80ea239f576ca04e775336bdc7da36f36ca
--- /dev/null
+++ b/components/table_row/table_row.component.yml
@@ -0,0 +1,37 @@
+name: "(Table Row)"
+description: "Internal: to be used in the 'Table' component."
+group: Table
+links:
+  - "https://getbootstrap.com/docs/5.3/content/tables/"
+slots:
+  cells:
+    title: "Row cells"
+    description: "A sequence of cell components."
+props:
+  type: object
+  properties:
+    color:
+      title: "Row color"
+      type: string
+      enum:
+        - primary
+        - secondary
+        - success
+        - danger
+        - warning
+        - info
+        - light
+        - dark
+      "meta:enum":
+        primary: Primary
+        secondary: Secondary
+        success: Success
+        danger: Danger
+        warning: Warning
+        info: Info
+        light: Light
+        dark: Dark
+    active:
+      title: Active
+      description: "Active state"
+      type: boolean
diff --git a/components/table_row/table_row.preview.story.yml b/components/table_row/table_row.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bc0b3e3cc57866605aef9cfe223c6602a61f1ae3
--- /dev/null
+++ b/components/table_row/table_row.preview.story.yml
@@ -0,0 +1,3 @@
+name: Preview
+props:
+  active: false
diff --git a/templates/patterns/table_row/pattern-table-row.html.twig b/components/table_row/table_row.twig
similarity index 100%
rename from templates/patterns/table_row/pattern-table-row.html.twig
rename to components/table_row/table_row.twig
diff --git a/components/toast/toast.component.yml b/components/toast/toast.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dd2559e3c83131bac2982a9613e8cb66d89a5096
--- /dev/null
+++ b/components/toast/toast.component.yml
@@ -0,0 +1,49 @@
+name: Toast
+description: "Push notifications to your visitors with a toast, a lightweight and easily customizable alert message."
+group: Toast
+links:
+  - "https://getbootstrap.com/docs/5.3/components/toast/"
+slots:
+  header:
+    title: Header
+    description: "Toast header."
+  content:
+    title: "Content toast"
+    description: "The toast item content."
+props:
+  type: object
+  properties:
+    delay:
+      title: "Hide delay"
+      description: "The duration before automatically hide the toast. In ms. 0 to disable the automatic hide."
+      type: number
+      default: 5000
+    role:
+      title: Role
+      description: "Adapt the role level depending on the content. If it’s an important message like an error, use alert, otherwise use status."
+      type: string
+      enum:
+        - alert
+        - status
+        - log
+      "meta:enum":
+        alert: "Alert (Default)"
+        status: Status
+        log: Log
+    flex_wrapper:
+      title: "Add inside flex wrapper"
+      description: "Add a flex wrapper inside the toast, see https://getbootstrap.com/docs/5.3/components/toasts/#custom-content. Default: false"
+      type: boolean
+    hide_close_button:
+      title: "Hide close button"
+      description: "If checked, you will have to provide a close button in another way. Default: false"
+      type: boolean
+    close_button_variant:
+      title: "Close button variant"
+      type: string
+      enum:
+        - default
+        - white
+      "meta:enum":
+        default: "Default (Default)"
+        white: White
diff --git a/components/toast/toast.preview.story.yml b/components/toast/toast.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d303bd0fe2c0c23b295a2577db8287ceab6fe299
--- /dev/null
+++ b/components/toast/toast.preview.story.yml
@@ -0,0 +1,29 @@
+name: Preview
+slots:
+  header:
+    - theme: image
+      uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
+      attributes:
+        class:
+          - rounded
+          - me-2
+    - type: html_tag
+      tag: strong
+      value: Bootstrap
+      attributes:
+        class:
+          - me-auto
+    - type: html_tag
+      tag: small
+      value: "11 mins ago"
+  content: "Hello, world! This is a toast message."
+props:
+  attributes:
+    class:
+      - show
+  delay: 5000
+  role: alert
+  flex_wrapper: false
+  hide_close_button: false
+  close_button_variant: default
+library_wrapper: "<div class=\"toast-container position-static\">{{ _story }}</div"
diff --git a/templates/patterns/toast/pattern-toast.html.twig b/components/toast/toast.twig
similarity index 78%
rename from templates/patterns/toast/pattern-toast.html.twig
rename to components/toast/toast.twig
index 9ace73a99c5fffb8c1ffd39634c9009fc6c469dc..d0d6afcd64817f6f9acc6ee6f4ee14d34a49415e 100644
--- a/templates/patterns/toast/pattern-toast.html.twig
+++ b/components/toast/toast.twig
@@ -29,11 +29,12 @@
       {{ header }}
 
       {% if not hide_close_button %}
-        {{ pattern('close_button', {
-          attributes: create_attribute({
-            'data-bs-dismiss': 'toast'
-          })
-        }, close_button_variant) }}
+        {{ include('ui_suite_bootstrap:close_button', {
+          attributes: {
+            'data-bs-dismiss': 'toast',
+          },
+          variant: close_button_variant,
+        }, with_context = false) }}
       {% endif %}
     </div>
   {% endif %}
@@ -45,16 +46,16 @@
   {% endif %}
 
   {% if not hide_close_button and not header %}
-    {{ pattern('close_button', {
-      variant: close_button_variant,
-      attributes: create_attribute({
+    {{ include('ui_suite_bootstrap:close_button', {
+      attributes: {
         'data-bs-dismiss': 'toast',
         'class': [
           'me-2',
-          'm-auto'
-        ]
-      })
-    }) }}
+          'm-auto',
+        ],
+      },
+      variant: close_button_variant,
+    }, with_context = false) }}
   {% endif %}
 
   {% if flex_wrapper %}
diff --git a/components/toast_container/toast_container.component.yml b/components/toast_container/toast_container.component.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ecc9f88712347e827151f8d0d6034501f08142bd
--- /dev/null
+++ b/components/toast_container/toast_container.component.yml
@@ -0,0 +1,8 @@
+name: "Toast container"
+description: "You can stack toasts by wrapping them in a toast container, which will vertically add some spacing."
+group: Toast
+links:
+  - "https://getbootstrap.com/docs/5.3/components/toasts/#stacking"
+slots:
+  items:
+    title: "Toast items"
diff --git a/components/toast_container/toast_container.preview.story.yml b/components/toast_container/toast_container.preview.story.yml
new file mode 100644
index 0000000000000000000000000000000000000000..81525a1688876e78e0f81f05ea73436e333f5fb6
--- /dev/null
+++ b/components/toast_container/toast_container.preview.story.yml
@@ -0,0 +1,112 @@
+name: Preview
+slots:
+  items:
+    - type: component
+      attributes:
+        class:
+          - show
+      component: "ui_suite_bootstrap:toast"
+      slots:
+        header:
+          - theme: image
+            uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
+            attributes:
+              class:
+                - rounded
+                - me-2
+          - type: html_tag
+            tag: strong
+            value: Bootstrap
+            attributes:
+              class:
+                - me-auto
+          - type: html_tag
+            tag: small
+            value: "just now"
+            attributes:
+              class:
+                - text-muted
+        content: "See? Just like this."
+    - type: component
+      attributes:
+        class:
+          - show
+      component: "ui_suite_bootstrap:toast"
+      slots:
+        header:
+          - theme: image
+            uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
+            attributes:
+              class:
+                - rounded
+                - me-2
+          - type: html_tag
+            tag: strong
+            value: Bootstrap
+            attributes:
+              class:
+                - me-auto
+          - type: html_tag
+            tag: small
+            value: "2 seconds ago"
+            attributes:
+              class:
+                - text-muted
+        content: "Heads up, toasts will stack automatically"
+    - type: component
+      attributes:
+        class:
+          - show
+      component: "ui_suite_bootstrap:toast"
+      slots:
+        content: "Hello, world! This is a toast message."
+      props:
+        flex_wrapper: true
+    - type: component
+      attributes:
+        class:
+          - show
+      component: "ui_suite_bootstrap:toast"
+      slots:
+        content:
+          - markup: "Hello, world! This is a toast message."
+          - type: html_tag
+            tag: div
+            attributes:
+              class:
+                - mt-2
+                - pt-2
+                - border-top
+          - type: component
+            component: "ui_suite_bootstrap:button"
+            slots:
+              label: "Take action"
+            props:
+              variant: primary__sm
+          - type: component
+            attributes:
+              data-bs-dismiss: toast
+            component: "ui_suite_bootstrap:button"
+            slots:
+              label: Close
+            props:
+              variant: secondary__sm
+      props:
+        hide_close_button: true
+    - type: component
+      attributes:
+        class:
+          - show
+          - align-items-center
+          - text-bg-primary
+          - border-0
+      component: "ui_suite_bootstrap:toast"
+      slots:
+        content: "Hello, world! This is a toast message."
+      props:
+        flex_wrapper: true
+        close_button_variant: white
+props:
+  attributes:
+    class:
+      - position-static
diff --git a/templates/patterns/toast_container/pattern-toast-container.html.twig b/components/toast_container/toast_container.twig
similarity index 100%
rename from templates/patterns/toast_container/pattern-toast-container.html.twig
rename to components/toast_container/toast_container.twig
diff --git a/composer.json b/composer.json
index 1ce1cb7b70fe1678cf43b404e5a63a1ab5fc3265..b55391093f1c12b64c848130c8dc8634b2472954 100644
--- a/composer.json
+++ b/composer.json
@@ -5,12 +5,12 @@
     "type": "drupal-theme",
     "require": {
         "drupal/layout_options": "^1.4",
-        "drupal/ui_patterns": "^1.10",
-        "drupal/ui_patterns_settings": "^2.2",
+        "drupal/ui_patterns": "^2.0",
         "drupal/ui_styles": "^1.7"
     },
     "require-dev": {
         "drupal/gin_lb": "^1.0",
+        "drupal/sdc_devel": "^1.0",
         "drupal/ui_skins": "^1.0"
     },
     "suggest": {
diff --git a/docs/Out-of-scope.md b/docs/Out-of-scope.md
index b51a932febfcad0f681260e799c470838666c57c..07e7474ebdae9da9a8f1ff2147dc20f8b3a85e46 100644
--- a/docs/Out-of-scope.md
+++ b/docs/Out-of-scope.md
@@ -15,6 +15,12 @@ issues and provide MR to add support.
 
 ### Layouts
 
+#### Columns
+
+- [Column breaks](https://getbootstrap.com/docs/5.2/layout/columns/#column-breaks)
+- [Margin utilities](https://getbootstrap.com/docs/5.2/layout/columns/#margin-utilities):
+  Responsive variations have not been added in the styles.
+
 #### CSS Grid
 
 [Bootstrap documentation](https://getbootstrap.com/docs/5.3/layout/css-grid/)
@@ -22,7 +28,6 @@ issues and provide MR to add support.
 [Drupal.org issue](https://www.drupal.org/project/ui_suite_bootstrap/issues/3292505):
 Not enabled by default in Bootstrap and potential conflict with default grid system.
 
-
 ### Forms
 
 - [Toggle buttons](https://getbootstrap.com/docs/5.3/forms/checks-radios/#toggle-buttons)
@@ -31,7 +36,6 @@ Not enabled by default in Bootstrap and potential conflict with default grid sys
 - [Segmented buttons](https://getbootstrap.com/docs/5.3/forms/input-group/#segmented-buttons)
 - [Custom styles](https://getbootstrap.com/docs/5.3/forms/validation/#custom-styles)
 
-
 ### Components
 
 - [Placeholders](https://getbootstrap.com/docs/5.3/components/placeholders/)
@@ -39,7 +43,6 @@ Not enabled by default in Bootstrap and potential conflict with default grid sys
 - [Scrollspy](https://getbootstrap.com/docs/5.3/components/scrollspy/)
 - [Tooltips](https://getbootstrap.com/docs/5.3/components/tooltips/)
 
-
 ### Helpers
 
 #### Stacks
@@ -49,7 +52,6 @@ Not enabled by default in Bootstrap and potential conflict with default grid sys
 [Drupal.org issue](https://www.drupal.org/project/ui_suite_bootstrap/issues/3292606):
 The matching styles will not be added.
 
-
 ### Utilities
 
 #### Borders
diff --git a/src/Element/ElementProcessActions.php b/src/Element/ElementProcessActions.php
new file mode 100644
index 0000000000000000000000000000000000000000..a32cc375c935a6592f85cfd6d9babc4a1f3e2876
--- /dev/null
+++ b/src/Element/ElementProcessActions.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\ui_suite_bootstrap\Utility\Element;
+
+/**
+ * Element Process methods for actions.
+ */
+class ElementProcessActions {
+
+  /**
+   * Processes an actions form element.
+   */
+  public static function processActions(array &$element, FormStateInterface $form_state, array &$complete_form): array {
+    $element_object = Element::create($element);
+    if (!$element_object->getProperty('isLayoutBuilder')) {
+      return $element;
+    }
+
+    $element_object->addClass('mt-3');
+
+    // Change links into buttons.
+    foreach ($element_object->children() as $child) {
+      if (!$child->isType('link')) {
+        continue;
+      }
+      $child->addClass('btn');
+      $child->colorize();
+    }
+
+    return $element;
+  }
+
+}
diff --git a/src/HookHandler/ElementInfoAlter.php b/src/HookHandler/ElementInfoAlter.php
index 3d5f263e194fa882eb313699078ccb4b214b26b2..c96760e75ebd92afba18598c80e07670bd0b4e17 100644
--- a/src/HookHandler/ElementInfoAlter.php
+++ b/src/HookHandler/ElementInfoAlter.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace Drupal\ui_suite_bootstrap\HookHandler;
 
 use Drupal\ui_suite_bootstrap\Element\ElementPreRenderDropbutton;
+use Drupal\ui_suite_bootstrap\Element\ElementProcessActions;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessCheckboxes;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessInputGroup;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessRadios;
@@ -107,6 +108,14 @@ class ElementInfoAlter {
     // Sort the types for easier debugging.
     \ksort($info, \SORT_NATURAL);
 
+    // Actions.
+    if (isset($info['actions'])) {
+      $info['actions']['#process'][] = [
+        ElementProcessActions::class,
+        'processActions',
+      ];
+    }
+
     // Checkbox.
     if (isset($info['checkbox'])) {
       foreach (static::CHECKBOX_PROPERTIES as $property => $property_default_value) {
diff --git a/src/HookHandler/FormAlter.php b/src/HookHandler/FormAlter.php
index 0f78c97d5a22b28b4cb32ab27a3174e8f79e61f9..71d1150a011da4f51877db2dcef7633e9e4e4c93 100644
--- a/src/HookHandler/FormAlter.php
+++ b/src/HookHandler/FormAlter.php
@@ -32,9 +32,14 @@ class FormAlter {
     }
 
     if ($this->isLayoutBuilderForm($form, $form_id)) {
+      // Even with the after build, some elements like actions is not marked,
+      // so marked it directly.
+      static::markLayoutBuilder($form);
+      // Use #after_build otherwise we do not have access to all subform
+      // elements.
       $form['#after_build'][] = [
         static::class,
-        'afterBuildDisableDetailsAccordion',
+        'afterBuildMarkLayoutBuilder',
       ];
     }
   }
@@ -50,8 +55,8 @@ class FormAlter {
   /**
    * Form element #after_build callback.
    */
-  public static function afterBuildDisableDetailsAccordion(array $element, FormStateInterface $form_state): array {
-    static::disableDetailsAccordion($element);
+  public static function afterBuildMarkLayoutBuilder(array $element, FormStateInterface $form_state): array {
+    static::markLayoutBuilder($element);
     return $element;
   }
 
@@ -93,6 +98,7 @@ class FormAlter {
       'layout_builder_block_move',
       'layout_builder_configure_section',
       'layout_builder_remove_block',
+      'layout_builder_remove_section',
       'layout_builder_update_block',
       'media_image_edit_form',
       'media_library_add_form_oembed',
@@ -126,20 +132,17 @@ class FormAlter {
   }
 
   /**
-   * Set bootstrap_accordion FALSE to all layout builder details form elements.
+   * Set isLayoutBuilder to all form elements.
    *
    * @param array $form
    *   The form or form element which children should have form id attached.
    */
-  protected static function disableDetailsAccordion(array &$form): void {
+  protected static function markLayoutBuilder(array &$form): void {
     foreach (Element::children($form) as $child) {
-      if (isset($form[$child]['#type'])
-        && $form[$child]['#type'] == 'details'
-        && !isset($form[$child]['#bootstrap_accordion'])
-      ) {
-        $form[$child]['#bootstrap_accordion'] = FALSE;
+      if (!isset($form[$child]['#isLayoutBuilder'])) {
+        $form[$child]['#isLayoutBuilder'] = TRUE;
       }
-      static::disableDetailsAccordion($form[$child]);
+      static::markLayoutBuilder($form[$child]);
     }
   }
 
diff --git a/src/HookHandler/FormMediaLibraryAddFormAlter.php b/src/HookHandler/FormMediaLibraryAddFormAlter.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d2928db04a720bbdd0b39ea7fc8f7d70ee27b78
--- /dev/null
+++ b/src/HookHandler/FormMediaLibraryAddFormAlter.php
@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\HookHandler;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+/**
+ * Hook implementation.
+ */
+class FormMediaLibraryAddFormAlter {
+
+  /**
+   * Hook implementation.
+   *
+   * @param array $form
+   *   The form structure.
+   * @param \Drupal\Core\Form\FormStateInterface $formState
+   *   The form state.
+   * @param string $formId
+   *   The form ID.
+   */
+  public function alter(array &$form, FormStateInterface $formState, string $formId): void {
+    $this->styleWrapper($form);
+    $this->styleCreatedMediaList($form);
+  }
+
+  /**
+   * Style the form wrapper, all steps.
+   *
+   * @param array $form
+   *   The form structure.
+   */
+  protected function styleWrapper(array &$form): void {
+    $form['#attributes']['class'][] = 'row';
+    $form['#attributes']['class'][] = 'm-1';
+    $form['#attributes']['class'][] = 'mb-3';
+    $form['#attributes']['class'][] = 'p-2';
+    $form['#attributes']['class'][] = 'border';
+  }
+
+  /**
+   * Style the created media, second step.
+   *
+   * @param array $form
+   *   The form structure.
+   */
+  protected function styleCreatedMediaList(array &$form): void {
+    if (!isset($form['media'])) {
+      return;
+    }
+
+    $form['media']['#attributes']['class'][] = 'list-unstyled';
+
+    foreach (Element::children($form['media']) as $key) {
+      $media = &$form['media'][$key];
+
+      $media['#wrapper_attributes']['class'][] = 'row';
+
+      $media['preview']['#attributes']['class'][] = 'col-2';
+      $media['preview']['#attributes']['class'][] = 'bg-light';
+      $media['preview']['#attributes']['class'][] = 'd-flex';
+      $media['preview']['#attributes']['class'][] = 'align-items-center';
+      $media['preview']['#attributes']['class'][] = 'justify-content-center';
+
+      $media['fields']['#attributes']['class'][] = 'col-10';
+      $media['fields']['#attributes']['class'][] = 'mt-3';
+
+      // Need CSS for the special 'right', so handle all properties with CSS.
+      $media['remove_button']['#attributes']['class'][] = 'media-added-remove-button';
+    }
+  }
+
+}
diff --git a/src/HookHandler/FormViewsExposedFormAlter.php b/src/HookHandler/FormViewsExposedFormAlter.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb9d8183c6dae8c97b79b758946b2d1d36b3202a
--- /dev/null
+++ b/src/HookHandler/FormViewsExposedFormAlter.php
@@ -0,0 +1,46 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\HookHandler;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Views exposed form.
+ */
+class FormViewsExposedFormAlter {
+
+  /**
+   * Views exposed form.
+   *
+   * @param array $form
+   *   The form structure.
+   * @param \Drupal\Core\Form\FormStateInterface $formState
+   *   The form state.
+   * @param string $form_id
+   *   The form ID.
+   */
+  public function alter(array &$form, FormStateInterface $formState, string $form_id): void {
+    if (!\str_starts_with($form['#id'], 'views-exposed-form-media-library-widget')) {
+      return;
+    }
+
+    $form['#attributes']['class'][] = 'row';
+    $form['#attributes']['class'][] = 'row-cols-auto';
+    $form['#attributes']['class'][] = 'align-items-end';
+    $form['#attributes']['class'][] = 'm-1';
+    $form['#attributes']['class'][] = 'mb-3';
+    $form['#attributes']['class'][] = 'p-2';
+    $form['#attributes']['class'][] = 'border';
+    if (isset($form['actions'])) {
+      $form['actions']['#attributes']['class'][] = 'mb-3';
+    }
+
+    // Reset button.
+    if (isset($form['actions']['reset'])) {
+      $form['actions']['reset']['#attributes']['class'][] = 'ms-2';
+    }
+  }
+
+}
diff --git a/src/HookHandler/PreprocessBreadcrumb.php b/src/HookHandler/PreprocessBreadcrumb.php
deleted file mode 100644
index 77a14a25fc7b8f7c80fb507e30fa41bef5c55bfc..0000000000000000000000000000000000000000
--- a/src/HookHandler/PreprocessBreadcrumb.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\ui_suite_bootstrap\HookHandler;
-
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
-
-/**
- * Ensure breadcrumb structure fits into links prop structure.
- */
-class PreprocessBreadcrumb {
-
-  /**
-   * Ensure breadcrumb structure fits into links prop structure.
-   *
-   * @param array $variables
-   *   The preprocessed variables.
-   */
-  public function preprocess(array &$variables): void {
-    $variables['breadcrumb'] = LinksSettingType::normalize($variables['breadcrumb']);
-  }
-
-}
diff --git a/src/HookHandler/PreprocessDetailsAccordion.php b/src/HookHandler/PreprocessDetailsAccordion.php
index a09913a56461ba45ec5492843de0d76b9a3ec1c0..eeec4dc4b07746b5073721c9eb804b0b07784f01 100644
--- a/src/HookHandler/PreprocessDetailsAccordion.php
+++ b/src/HookHandler/PreprocessDetailsAccordion.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\ui_suite_bootstrap\HookHandler;
 
+use Drupal\Core\Template\Attribute;
 use Drupal\ui_suite_bootstrap\Utility\Variables;
 
 /**
@@ -28,6 +29,18 @@ class PreprocessDetailsAccordion extends PreprocessFormElement {
       return;
     }
 
+    /** @var array $accordion_attributes */
+    $accordion_attributes = $this->element->getProperty('accordion_attributes', []);
+    $accordion_attributes = new Attribute($accordion_attributes);
+    if ($this->element->getProperty('isLayoutBuilder')) {
+      $accordion_attributes->addClass('accordion-flush');
+      $style = $accordion_attributes->offsetGet('style') ?? '';
+      $accordion_attributes->setAttribute('style', $style . '--bs-accordion-body-padding-x: 0');
+    }
+    else {
+      $accordion_attributes->addClass('mb-3');
+    }
+
     // Remove Core library for details HTML tag.
     /** @var array $attached */
     $attached = $this->element->getProperty('attached', []);
@@ -39,6 +52,9 @@ class PreprocessDetailsAccordion extends PreprocessFormElement {
     }
     $this->element->setProperty('attached', $attached);
 
+    // Cannot use map directly because of the attributes' management.
+    $this->variables->offsetSet('accordion_attributes', $accordion_attributes);
+
     $this->validation();
   }
 
diff --git a/src/HookHandler/PreprocessFieldset.php b/src/HookHandler/PreprocessFieldset.php
index 8911a26379c19499a33f5e5118cb9aec84f6571b..f4cbf3462c5d33ab886efadd8f84c9a54638fc7e 100644
--- a/src/HookHandler/PreprocessFieldset.php
+++ b/src/HookHandler/PreprocessFieldset.php
@@ -32,6 +32,7 @@ class PreprocessFieldset extends PreprocessFormElement {
     /** @var array $wrapper_attributes */
     $wrapper_attributes = $this->element->getProperty('wrapper_attributes', []);
     $wrapper_attributes = new Attribute($wrapper_attributes);
+    $wrapper_attributes->addClass('mb-3');
 
     /** @var array $label_attributes */
     $label_attributes = $this->element->getProperty('label_attributes', []);
@@ -46,15 +47,18 @@ class PreprocessFieldset extends PreprocessFormElement {
     if ($this->element->getProperty('title_display') == 'inline' || $this->element->getProperty('_title_display') == 'inline') {
       $wrapper_attributes->addClass([
         'row',
-        'mb-3',
       ]);
       $label_attributes->addClass('col-form-label');
     }
-    // Display fieldset as card.
+    // In Layout Builder, ensure the fieldset legend has normal size for
+    // checkboxes and radios.
+    elseif ($this->element->isType(['checkboxes', 'radios']) && $this->element->getProperty('isLayoutBuilder')) {
+      $label_attributes->addClass('fs-6');
+    }
+    // Display fieldset as card by default.
     else {
       $wrapper_attributes->addClass([
         'card',
-        'mb-3',
       ]);
       $label_attributes->addClass('card-header');
       $inner_wrapper_attributes->addClass('card-body');
diff --git a/src/HookHandler/PreprocessFilterTips.php b/src/HookHandler/PreprocessFilterTips.php
index 558090a53ff777aca83f53b2aea05f9639fbf7b1..82a53fe556fb443bfe85bdac2c6b0e28666a62de 100644
--- a/src/HookHandler/PreprocessFilterTips.php
+++ b/src/HookHandler/PreprocessFilterTips.php
@@ -68,16 +68,20 @@ class PreprocessFilterTips implements ContainerInjectionInterface {
     $current_format_id = $current_format ? $current_format->id() : FALSE;
 
     $build = [
-      '#type' => 'pattern',
-      '#id' => 'nav',
-      '#variant' => 'tabs',
+      '#type' => 'component',
+      '#component' => 'ui_suite_bootstrap:nav',
+      '#props' => [
+        'variant' => 'tabs',
+        'items' => [],
+      ],
+      '#slots' => [
+        'tab_content' => [],
+      ],
       '#attributes' => [
         'class' => [
           'mb-3',
         ],
       ],
-      '#items' => [],
-      '#tab_content' => [],
     ];
 
     foreach (\filter_formats($this->currentUser) as $format_id => $format) {
@@ -87,8 +91,8 @@ class PreprocessFilterTips implements ContainerInjectionInterface {
       }
       $active = $current_format_id === $format_id;
 
-      $build['#items'][] = $this->getTab($format, $active);
-      $build['#tab_content'][] = $this->getPane($format);
+      $build['#props']['items'][] = $this->getTab($format, $active);
+      $build['#slots']['tab_content'][] = $this->getPane($format);
     }
 
     $variables['tips'] = $build;
diff --git a/src/HookHandler/PreprocessLinksDropbutton.php b/src/HookHandler/PreprocessLinksDropbutton.php
index d18cf7d9a3f5acc2fcf890175d50152bb9c314c2..b9329869e43e43cb7b61152a733e8618085e69be 100644
--- a/src/HookHandler/PreprocessLinksDropbutton.php
+++ b/src/HookHandler/PreprocessLinksDropbutton.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\ui_suite_bootstrap\HookHandler;
 
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
+use Drupal\ui_patterns\Plugin\UiPatterns\PropType\LinksPropType;
 use Drupal\ui_suite_bootstrap\Utility\Bootstrap;
 
 /**
@@ -23,7 +23,7 @@ class PreprocessLinksDropbutton {
       return;
     }
 
-    $links = LinksSettingType::normalize(\array_filter(
+    $links = LinksPropType::normalize(\array_filter(
       $variables['links'],
     ));
     $first_link = \array_shift($links);
@@ -43,14 +43,18 @@ class PreprocessLinksDropbutton {
     }
 
     $variables['dropdown'] = [
-      '#type' => 'pattern',
-      '#id' => 'dropdown',
-      '#title' => $first_link['title'],
-      '#button_url' => $first_link['url'] ?? '',
-      '#button_attributes' => $first_link['attributes'],
-      '#button_variant' => $button_variant,
-      '#button_split' => !empty($links),
-      '#content' => empty($links) ? [] : $links,
+      '#type' => 'component',
+      '#component' => 'ui_suite_bootstrap:dropdown',
+      '#props' => [
+        'button_url' => $first_link['url'] ?? '',
+        'button_attributes' => $first_link['attributes'] ?? NULL,
+        'button_variant' => $button_variant,
+        'button_split' => !empty($links),
+        'content' => empty($links) ? [] : $links,
+      ],
+      '#slots' => [
+        'title' => $first_link['title'],
+      ],
       '#attributes' => $variables['attributes'],
     ];
   }
diff --git a/src/HookHandler/PreprocessLinksMediaLibraryMenu.php b/src/HookHandler/PreprocessLinksMediaLibraryMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..9a1114984a4ef2349ba5e59b2ea50a2e6ca9cd22
--- /dev/null
+++ b/src/HookHandler/PreprocessLinksMediaLibraryMenu.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\HookHandler;
+
+use Drupal\ui_patterns\Plugin\UiPatterns\PropType\LinksPropType;
+
+/**
+ * Ensure links structure fits into list group structure.
+ */
+class PreprocessLinksMediaLibraryMenu {
+
+  /**
+   * Ensure links structure fits into list group structure.
+   *
+   * @param array $variables
+   *   The preprocessed variables.
+   */
+  public function preprocess(array &$variables): void {
+    if (empty($variables['links'])) {
+      return;
+    }
+
+    $variables['preprocessed_items'] = LinksPropType::normalize(\array_filter(
+      $variables['links'],
+    ));
+  }
+
+}
diff --git a/src/HookHandler/PreprocessMenu.php b/src/HookHandler/PreprocessMenu.php
deleted file mode 100644
index d32754b7c738dcca3dfce27bcfa153fe9b19aa63..0000000000000000000000000000000000000000
--- a/src/HookHandler/PreprocessMenu.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\ui_suite_bootstrap\HookHandler;
-
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
-
-/**
- * Ensure menu structure fits into links prop structure.
- */
-class PreprocessMenu {
-
-  /**
-   * Ensure menu structure fits into links prop structure.
-   *
-   * @param array $variables
-   *   The preprocessed variables.
-   */
-  public function preprocess(array &$variables): void {
-    $variables['preprocessed_items'] = LinksSettingType::normalize($variables['items']);
-  }
-
-}
diff --git a/src/HookHandler/PreprocessMenuLocalTasks.php b/src/HookHandler/PreprocessMenuLocalTasks.php
index 8b39f5ca8138282811553f7197fe97781caa3d7f..1bb2108e033ba982399c630008d6c858cbfe44ea 100644
--- a/src/HookHandler/PreprocessMenuLocalTasks.php
+++ b/src/HookHandler/PreprocessMenuLocalTasks.php
@@ -6,7 +6,6 @@ namespace Drupal\ui_suite_bootstrap\HookHandler;
 
 use Drupal\Component\Utility\SortArray;
 use Drupal\Core\Access\AccessResultAllowed;
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
 
 /**
  * Prepare local task link for component.
@@ -60,8 +59,7 @@ class PreprocessMenuLocalTasks {
           'title' => $menuLocalTask['#link']['title'],
         ];
       }
-
-      $variables['preprocessed_items_' . $type] = LinksSettingType::normalize($preparedLinks);
+      $variables['preprocessed_items_' . $type] = $preparedLinks;
     }
   }
 
diff --git a/src/HookHandler/PreprocessPager.php b/src/HookHandler/PreprocessPager.php
index c3646e57d1c2dc54335c767c8d1961f9f80872fa..b00d716da17c7cf8fc2101a5810d56225b33022f 100644
--- a/src/HookHandler/PreprocessPager.php
+++ b/src/HookHandler/PreprocessPager.php
@@ -6,7 +6,6 @@ namespace Drupal\ui_suite_bootstrap\HookHandler;
 
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Template\Attribute;
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
 
 /**
  * Ensure pager structure fits into links prop structure.
@@ -27,26 +26,23 @@ class PreprocessPager {
     }
     $this->setLinksAriaLabel($variables['items']);
 
-    $before = LinksSettingType::normalize(\array_filter([
-      $variables['items']['first'] ?? [],
-      $variables['items']['previous'] ?? [],
-    ]));
-
-    $pages = LinksSettingType::normalize($variables['items']['pages'] ?? []);
-    if (isset($variables['current'])) {
-      foreach ($pages as $key => $page) {
-        if ($page['title'] == $variables['current']) {
-          unset($pages[$key]['url']);
-        }
+    $pages = $variables['items']['pages'] ?? [];
+    foreach ($pages as $key => $page) {
+      // Set item text now, as the array_merge will reorder items.
+      $pages[$key]['text'] = $key;
+      // The current item should not be a link.
+      if (isset($variables['current']) && $key == $variables['current']) {
+        unset($pages[$key]['href']);
       }
     }
 
-    $after = LinksSettingType::normalize(\array_filter([
+    $variables['preprocessed_items'] = \array_merge(\array_filter([
+      $variables['items']['first'] ?? [],
+      $variables['items']['previous'] ?? [],
+    ]), $pages, \array_filter([
       $variables['items']['next'] ?? [],
       $variables['items']['last'] ?? [],
     ]));
-
-    $variables['preprocessed_items'] = \array_merge($before, $pages, $after);
   }
 
   /**
diff --git a/src/HookHandler/PreprocessViewsMiniPager.php b/src/HookHandler/PreprocessViewsMiniPager.php
index 45fd0c52f9adbe0fd50dead69cfc23e2038597d1..c02bf7794700c9aa96b1cba226b8a6a74cdc5c58 100644
--- a/src/HookHandler/PreprocessViewsMiniPager.php
+++ b/src/HookHandler/PreprocessViewsMiniPager.php
@@ -4,8 +4,6 @@ declare(strict_types=1);
 
 namespace Drupal\ui_suite_bootstrap\HookHandler;
 
-use Drupal\ui_patterns_settings\Plugin\UiPatterns\SettingType\LinksSettingType;
-
 /**
  * Ensure views mini pager structure fits into links prop structure.
  */
@@ -23,13 +21,13 @@ class PreprocessViewsMiniPager extends PreprocessPager {
     }
     $this->setLinksAriaLabel($variables['items']);
 
-    $variables['preprocessed_items'] = LinksSettingType::normalize(\array_filter([
+    $variables['preprocessed_items'] = \array_filter([
       $variables['items']['previous'] ?? [],
       [
         'title' => $variables['items']['current'],
       ],
       $variables['items']['next'] ?? [],
-    ]));
+    ]);
   }
 
 }
diff --git a/src/HookHandler/PreprocessViewsViewTable.php b/src/HookHandler/PreprocessViewsViewTable.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a82bb456762d40c00e045b915592a18978dcb2e
--- /dev/null
+++ b/src/HookHandler/PreprocessViewsViewTable.php
@@ -0,0 +1,97 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\HookHandler;
+
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Prepare header and row cells.
+ */
+class PreprocessViewsViewTable implements ContainerInjectionInterface {
+
+  use StringTranslationTrait;
+
+  public function __construct(
+    protected RendererInterface $renderer,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container): static {
+    return new static(
+      $container->get('renderer')
+    );
+  }
+
+  /**
+   * Prepare header and row cells.
+   *
+   * @param array $variables
+   *   The preprocessed variables.
+   */
+  public function preprocess(array &$variables): void {
+    if (isset($variables['header'])) {
+      foreach ($variables['header'] as $key => $column) {
+        $column += [
+          'content' => '',
+          'sort_indicator' => [],
+          'url' => '',
+          'title' => '',
+          'wrapper_element' => '',
+        ];
+        $columnContent = $column['content'] . $this->renderer->render($column['sort_indicator']);
+
+        if ($column['url']) {
+          $variables['header'][$key]['preparedContent'] = [
+            '#type' => 'html_tag',
+            '#tag' => 'a',
+            '#value' => $columnContent,
+            '#attributes' => [
+              'href' => $column['url'],
+              'title' => $column['title'],
+              'rel' => 'nofollow',
+            ],
+            '#prefix' => $column['wrapper_element'] ? "<{$column['wrapper_element']}>" : '',
+            '#suffix' => $column['wrapper_element'] ? "</{$column['wrapper_element']}>" : '',
+          ];
+        }
+        else {
+          $variables['header'][$key]['preparedContent'] = [
+            '#markup' => new FormattableMarkup($columnContent, []),
+            '#prefix' => $column['wrapper_element'] ? "<{$column['wrapper_element']}>" : '',
+            '#suffix' => $column['wrapper_element'] ? "</{$column['wrapper_element']}>" : '',
+          ];
+        }
+      }
+    }
+
+    if (isset($variables['rows'])) {
+      foreach ($variables['rows'] as $rowKey => $row) {
+        foreach ($row['columns'] as $columnKey => $column) {
+          $column += [
+            'wrapper_element' => '',
+          ];
+
+          $columnContent = '';
+          foreach ($column['content'] as $content) {
+            $columnContent .= $this->renderer->render($content['separator']) . $this->renderer->render($content['field_output']);
+          }
+
+          $variables['rows'][$rowKey]['columns'][$columnKey]['preparedContent'] = [
+            '#markup' => new FormattableMarkup($columnContent, []),
+            '#prefix' => $column['wrapper_element'] ? "<{$column['wrapper_element']}>" : '',
+            '#suffix' => $column['wrapper_element'] ? "</{$column['wrapper_element']}>" : '',
+          ];
+        }
+      }
+    }
+  }
+
+}
diff --git a/src/HookHandler/ThemeSuggestionsAlter.php b/src/HookHandler/ThemeSuggestionsAlter.php
index d4d2d3f10a6f8042b9afa36702110da74ae78466..3fc4e7ec8fa982379ef9d3f05804d344c50a0650 100644
--- a/src/HookHandler/ThemeSuggestionsAlter.php
+++ b/src/HookHandler/ThemeSuggestionsAlter.php
@@ -85,13 +85,6 @@ class ThemeSuggestionsAlter implements ContainerInjectionInterface {
     $this->variables = Variables::create($variables);
     $this->element = $this->variables->element;
 
-    if ($this->element
-      && !$this->element->hasProperty('bootstrap_accordion')
-      && $this->isLayoutBuilderRoute($variables)
-    ) {
-      $this->element->setProperty('bootstrap_accordion', FALSE);
-    }
-
     if ($this->element && $this->element->getProperty('bootstrap_accordion', TRUE)) {
       $suggestions[] = 'details__accordion';
     }
diff --git a/src/HookHandler/ViewsPreRender.php b/src/HookHandler/ViewsPreRender.php
new file mode 100644
index 0000000000000000000000000000000000000000..3a2b18a3f92be3d1a6f502a6aa2592360b0ad63c
--- /dev/null
+++ b/src/HookHandler/ViewsPreRender.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_suite_bootstrap\HookHandler;
+
+use Drupal\views\ViewExecutable;
+
+/**
+ * Handle CSS classes.
+ */
+class ViewsPreRender {
+
+  /**
+   * Handle CSS classes for media library.
+   *
+   * @param \Drupal\views\ViewExecutable $view
+   *   The view.
+   *
+   * @see \claro_views_pre_render()
+   */
+  public function preRender(ViewExecutable $view): void {
+    if ($view->id() === 'media_library') {
+      if ($view->current_display === 'widget') {
+        if (\array_key_exists('media_library_select_form', $view->field)) {
+          $this->addClasses($view->field['media_library_select_form']->options['element_wrapper_class'], [
+            'position-absolute',
+            'ms-1',
+            'z-1',
+          ]);
+        }
+      }
+    }
+  }
+
+  /**
+   * Add classes.
+   *
+   * @param string $option
+   *   The existing option.
+   * @param string[] $classesToAdd
+   *   The classes to add.
+   */
+  protected function addClasses(string &$option, array $classesToAdd): void {
+    $classes = \preg_split('/\s+/', $option);
+    if (!\is_array($classes)) {
+      return;
+    }
+
+    $classes = \array_filter($classes);
+    $classes = \array_merge($classes, $classesToAdd);
+    $option = \implode(' ', \array_unique($classes));
+  }
+
+}
diff --git a/src/Utility/Element.php b/src/Utility/Element.php
index 3ed506e15102e5ce823d3770b750a08b358ea4d2..f1ec950f9e7d31fee233a49a6c994c4161919014 100644
--- a/src/Utility/Element.php
+++ b/src/Utility/Element.php
@@ -216,7 +216,7 @@ class Element extends DrupalAttributes {
    * Adds a specific Bootstrap class to color a button based on its text value.
    *
    * @param bool $override
-   *   Flag determining whether or not to override any existing set class.
+   *   Flag determining whether to override any existing set class.
    *
    * @return static
    *
@@ -225,8 +225,7 @@ class Element extends DrupalAttributes {
   public function colorize($override = TRUE) {
     $button = $this->isButton();
 
-    // @todo Be able to use for other stuff than button.
-    $prefix = $button ? 'btn' : 'has';
+    $prefix = 'btn';
 
     // List of classes, based on the prefix.
     $classes = [
diff --git a/templates/overrides/block/block--bare.html.twig b/templates/block/block--bare.html.twig
similarity index 100%
rename from templates/overrides/block/block--bare.html.twig
rename to templates/block/block--bare.html.twig
diff --git a/templates/overrides/block/block--local-actions-block.html.twig b/templates/block/block--local-actions-block.html.twig
similarity index 100%
rename from templates/overrides/block/block--local-actions-block.html.twig
rename to templates/block/block--local-actions-block.html.twig
diff --git a/templates/overrides/block/block--page-title-block.html.twig b/templates/block/block--page-title-block.html.twig
similarity index 100%
rename from templates/overrides/block/block--page-title-block.html.twig
rename to templates/block/block--page-title-block.html.twig
diff --git a/templates/overrides/block/block--system-branding-block.html.twig b/templates/block/block--system-branding-block.html.twig
similarity index 100%
rename from templates/overrides/block/block--system-branding-block.html.twig
rename to templates/block/block--system-branding-block.html.twig
diff --git a/templates/overrides/book/book-navigation.html.twig b/templates/book/book-navigation.html.twig
similarity index 100%
rename from templates/overrides/book/book-navigation.html.twig
rename to templates/book/book-navigation.html.twig
diff --git a/templates/overrides/comment/comment.html.twig b/templates/comment/comment.html.twig
similarity index 97%
rename from templates/overrides/comment/comment.html.twig
rename to templates/comment/comment.html.twig
index 4966982b7e016fe5fb39729ebb0eb3af3886d6f8..34aee6cb3a14bf71c9de7cd761817343a7451e69 100644
--- a/templates/overrides/comment/comment.html.twig
+++ b/templates/comment/comment.html.twig
@@ -91,15 +91,15 @@
     server which comments are new for the user. Rendering the final "new"
     indicator here would break the render cache.
     #}
-    {{ pattern('badge', {
-      'attributes': create_attribute({
+    {{ include('ui_suite_bootstrap:badge', {
+      'attributes': {
         'class': [
           'hidden',
-          'text-bg-info'
+          'text-bg-info',
         ],
         'data-comment-timestamp': new_indicator_timestamp,
-      })
-    }) }}
+      }
+    }, with_context = false) }}
 
     {#
       Indicate the semantic relationship between parent and child comments for
diff --git a/templates/overrides/commerce/cart/commerce-cart-block.html.twig b/templates/commerce/cart/commerce-cart-block.html.twig
similarity index 50%
rename from templates/overrides/commerce/cart/commerce-cart-block.html.twig
rename to templates/commerce/cart/commerce-cart-block.html.twig
index 4c57c3fb8d154f6f65ee1385b30566e33af88261..9d93ca684c982a869d84b14c105b4429a3ee007c 100644
--- a/templates/overrides/commerce/cart/commerce-cart-block.html.twig
+++ b/templates/commerce/cart/commerce-cart-block.html.twig
@@ -1,24 +1,24 @@
 {# Use accordion if the content of the cart is displayed. #}
 {% if content %}
-  {{ pattern('accordion', {
-    'variant': 'default',
-    'attributes': attributes,
+  {{ include('ui_suite_bootstrap:accordion', {
     'content': [
-      pattern('accordion_item', {
+      include('ui_suite_bootstrap:accordion_item', {
         'title': count_text,
         'content': [
           content,
           links,
-        ]
-      })
-    ]
-  }) }}
+        ],
+      }, with_context = false),
+    ],
+    'attributes': attributes,
+    'variant': 'default',
+  }, with_context = false) }}
 {% else %}
-  <div{{ attributes}}>
-    {{ pattern('button', {
+  <div{{ attributes }}>
+    {{ include('ui_suite_bootstrap:button', {
+      'label': count_text,
       'variant': 'link',
       'url': url,
-      'label': count_text
-    }) }}
+    }, with_context = false) }}
   </div>
 {% endif %}
diff --git a/templates/commerce/cart/commerce-cart-empty-page.html.twig b/templates/commerce/cart/commerce-cart-empty-page.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..baa2680c9a83b2776fb1e87874798c85debc37ac
--- /dev/null
+++ b/templates/commerce/cart/commerce-cart-empty-page.html.twig
@@ -0,0 +1,13 @@
+{#
+/**
+ * @file
+ *
+ * Empty cart page template.
+ *
+ * @ingroup themeable
+ */
+#}
+{{ include('ui_suite_bootstrap:alert', {
+  'message': 'Your shopping cart is empty.'|t,
+  'variant': 'info',
+}, with_context = false) }}
diff --git a/templates/overrides/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig b/templates/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig
similarity index 75%
rename from templates/overrides/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig
rename to templates/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig
index 2843f71edd30d5fe9787919f28c103f69e8f249a..59427e1a448e636c13dd21ae8faf0f4590bd0419 100644
--- a/templates/overrides/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig
+++ b/templates/commerce/checkout/commerce-checkout-form--with-sidebar.html.twig
@@ -18,16 +18,16 @@
       </div>
     </div>
     <div class="col col-12 col-md-4">
-      {{ pattern('card', {
-        'variant': 'default',
+      {{ include('ui_suite_bootstrap:card', {
         'content': [
-          pattern('card_body', {
-            'heading_level': 3,
+          include('ui_suite_bootstrap:card_body', {
             'title': 'Order summary'|t,
-            'content': form.sidebar
-          })
-        ]
-      }) }}
+            'content': form.sidebar,
+            'heading_level': 3,
+          }, with_context = false),
+        ],
+        'variant': 'default',
+      }, with_context = false) }}
     </div>
   </div>
 
diff --git a/templates/overrides/commerce/checkout/commerce-checkout-form.html.twig b/templates/commerce/checkout/commerce-checkout-form.html.twig
similarity index 100%
rename from templates/overrides/commerce/checkout/commerce-checkout-form.html.twig
rename to templates/commerce/checkout/commerce-checkout-form.html.twig
diff --git a/templates/overrides/commerce/checkout/commerce-checkout-order-summary.html.twig b/templates/commerce/checkout/commerce-checkout-order-summary.html.twig
similarity index 100%
rename from templates/overrides/commerce/checkout/commerce-checkout-order-summary.html.twig
rename to templates/commerce/checkout/commerce-checkout-order-summary.html.twig
diff --git a/templates/commerce/checkout/commerce-checkout-progress.html.twig b/templates/commerce/checkout/commerce-checkout-progress.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b49814e9e88fb14d5c5399f6b5a86d4385e967a3
--- /dev/null
+++ b/templates/commerce/checkout/commerce-checkout-progress.html.twig
@@ -0,0 +1,46 @@
+{#
+/**
+ * @file
+ * Default theme implementation for the checkout progress.
+ *
+ * Available variables:
+ * - steps: An array of steps, where each step has the following keys:
+ *   - id: The step ID.
+ *   - label: The step label.
+ *   - position: 'previous', 'current' or 'next'.
+ *
+ * @ingroup themeable
+ */
+#}
+{# Prepare list group items. #}
+{% set items = [] %}
+{% for step in steps %}
+  {% set items = items|merge([{
+    '#type': 'component',
+    '#component': 'ui_suite_bootstrap:list_group_item',
+    '#slots': {
+      'content': step.label,
+    },
+    '#props': {
+      'attributes': {
+        'class': [
+          'checkout-progress--step',
+          'checkout-progress--step__' ~ step.position,
+          'flex-fill',
+        ],
+      },
+      'variant': 'primary',
+    },
+  }]) %}
+{% endfor %}
+
+{{ include('ui_suite_bootstrap:list_group', {
+  'items': items,
+  'attributes': {
+    'class': [
+      'checkout-progress',
+      'clearfix',
+    ],
+  },
+  'variant': 'numbered__horizontal',
+}, with_context = false) }}
diff --git a/templates/overrides/commerce/promotion/commerce-coupon-redemption-form.html.twig b/templates/commerce/promotion/commerce-coupon-redemption-form.html.twig
similarity index 100%
rename from templates/overrides/commerce/promotion/commerce-coupon-redemption-form.html.twig
rename to templates/commerce/promotion/commerce-coupon-redemption-form.html.twig
diff --git a/templates/overrides/file/file-link.html.twig b/templates/file/file-link.html.twig
similarity index 100%
rename from templates/overrides/file/file-link.html.twig
rename to templates/file/file-link.html.twig
diff --git a/templates/overrides/filter/filter-tips.html.twig b/templates/filter/filter-tips.html.twig
similarity index 100%
rename from templates/overrides/filter/filter-tips.html.twig
rename to templates/filter/filter-tips.html.twig
diff --git a/templates/overrides/image/image-widget.html.twig b/templates/image/image-widget.html.twig
similarity index 100%
rename from templates/overrides/image/image-widget.html.twig
rename to templates/image/image-widget.html.twig
diff --git a/templates/overrides/input/datetime-form.html.twig b/templates/input/datetime-form.html.twig
similarity index 100%
rename from templates/overrides/input/datetime-form.html.twig
rename to templates/input/datetime-form.html.twig
diff --git a/templates/overrides/input/datetime-wrapper.html.twig b/templates/input/datetime-wrapper.html.twig
similarity index 100%
rename from templates/overrides/input/datetime-wrapper.html.twig
rename to templates/input/datetime-wrapper.html.twig
diff --git a/templates/overrides/input/form-element.html.twig b/templates/input/form-element.html.twig
similarity index 100%
rename from templates/overrides/input/form-element.html.twig
rename to templates/input/form-element.html.twig
diff --git a/templates/overrides/input/input--button.html.twig b/templates/input/input--button.html.twig
similarity index 100%
rename from templates/overrides/input/input--button.html.twig
rename to templates/input/input--button.html.twig
diff --git a/templates/overrides/input/input.html.twig b/templates/input/input.html.twig
similarity index 100%
rename from templates/overrides/input/input.html.twig
rename to templates/input/input.html.twig
diff --git a/templates/overrides/input/select.html.twig b/templates/input/select.html.twig
similarity index 100%
rename from templates/overrides/input/select.html.twig
rename to templates/input/select.html.twig
diff --git a/templates/overrides/input/textarea.html.twig b/templates/input/textarea.html.twig
similarity index 100%
rename from templates/overrides/input/textarea.html.twig
rename to templates/input/textarea.html.twig
diff --git a/templates/overrides/media/media--bare.html.twig b/templates/media/media--bare.html.twig
similarity index 100%
rename from templates/overrides/media/media--bare.html.twig
rename to templates/media/media--bare.html.twig
diff --git a/templates/media/media--media-library.html.twig b/templates/media/media--media-library.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..5d6c631fec891e5b93e594c0f5376100e39b6d82
--- /dev/null
+++ b/templates/media/media--media-library.html.twig
@@ -0,0 +1,53 @@
+{#
+/**
+ * @file
+ * Theme override of a media item in the media library.
+ *
+ * This is used for media that the user can select from the grid of media
+ * items. It is not used for items that have already been selected in the
+ * corresponding field widget, or for items that have been previously selected
+ * before adding new media to the library.
+ *
+ * Available variables:
+ * - media: The entity with limited access to object properties and methods.
+ *   Only method names starting with "get", "has", or "is" and a few common
+ *   methods such as "id", "label", and "bundle" are available. For example:
+ *   - entity.getEntityTypeId() will return the entity type ID.
+ *   - entity.hasField('field_example') returns TRUE if the entity includes
+ *     field_example. (This does not indicate the presence of a value in this
+ *     field.)
+ *   Calling other methods, such as entity.delete(), will result in an exception.
+ *   See \Drupal\Core\Entity\EntityInterface for a full list of methods.
+ * - name: Name of the media.
+ * - content: Media content.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the main title tag that appears in the template.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the main title tag that appears in the template.
+ * - view_mode: View mode; for example, "teaser" or "full".
+ * - attributes: HTML attributes for the containing element.
+ * - title_attributes: Same as attributes, except applied to the main title
+ *   tag that appears in the template.
+ * - url: Direct URL of the media.
+ * - preview_attributes: HTML attributes for the preview wrapper.
+ * - metadata_attributes: HTML attributes for the expandable metadata area.
+ * - status: Whether or not the Media is published.
+ *
+ * @see template_preprocess_media()
+ *
+ * @ingroup themeable
+ */
+#}
+<article{{ attributes.addClass('card') }}>
+  {% if content %}
+    <div{{ preview_attributes.addClass(['js-media-library-item-preview', 'card-img-top', 'text-center', 'bg-light', 'text-dark']) }}>
+      {{ content|without('name') }}
+    </div>
+    <div{{ metadata_attributes.addClass('card-body') }}>
+      {{ name }}
+      {% if not status %}
+        <span class="badge text-bg-danger">{{ "unpublished"|t }}</span>
+      {% endif %}
+    </div>
+  {% endif %}
+</article>
diff --git a/templates/overrides/media/media.html.twig b/templates/media/media.html.twig
similarity index 100%
rename from templates/overrides/media/media.html.twig
rename to templates/media/media.html.twig
diff --git a/templates/media_library/media-library-item.html.twig b/templates/media_library/media-library-item.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..4717b15e7e82fe59be63e598fd49c36bf0c72c19
--- /dev/null
+++ b/templates/media_library/media-library-item.html.twig
@@ -0,0 +1,32 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a media library item.
+ *
+ * This is used when displaying selected media items, either in the field
+ * widget or in the "Additional selected media" area when adding new
+ * media items in the media library modal dialog.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - content: The content of the media library item, plus any additional
+ *   fields or elements surrounding it.
+ *
+ * @see template_preprocess_media_library_item()
+ *
+ * @ingroup themeable
+ */
+#}
+{%
+  set classes = [
+    'position-relative',
+    'col-12',
+    'col-cq-sm-6',
+    'col-cq-md-4',
+    'col-cq-lg-3',
+    'gy-3',
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {{ content }}
+</div>
diff --git a/templates/media_library/media-library-wrapper.html.twig b/templates/media_library/media-library-wrapper.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..59b5df0a3cd38860e92490016633bc94948586ec
--- /dev/null
+++ b/templates/media_library/media-library-wrapper.html.twig
@@ -0,0 +1,34 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a container used to wrap the media library's
+ * modal dialog interface.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - menu: The menu of available media types to choose from.
+ * - content: The form to add new media items, followed by the grid or table of
+ *   existing media items to choose from.
+ *
+ * @see template_preprocess_media_library_wrapper()
+ *
+ * @ingroup themeable
+ */
+#}
+{% set content_wrapper_attributes = create_attribute({
+  'class': [
+    menu ? 'col-8': 'col-12',
+    menu ? 'col-md-10': '',
+    menu ? 'border-start': '',
+]}) %}
+
+<div{{ attributes.addClass('row') }}>
+  {% if menu %}
+    <div class="col-4 col-md-2">
+      {{ menu }}
+    </div>
+  {% endif %}
+  <div{{ content_wrapper_attributes }}>
+    {{ content }}
+  </div>
+</div>
diff --git a/templates/overrides/menu/menu-local-action.html.twig b/templates/menu/menu-local-action.html.twig
similarity index 100%
rename from templates/overrides/menu/menu-local-action.html.twig
rename to templates/menu/menu-local-action.html.twig
diff --git a/templates/overrides/menu/menu-local-tasks.html.twig b/templates/menu/menu-local-tasks.html.twig
similarity index 73%
rename from templates/overrides/menu/menu-local-tasks.html.twig
rename to templates/menu/menu-local-tasks.html.twig
index 7aa08bbb7ca026fbd89db44036a7534f013e4fb9..d4570635a52ae517f64e063a9259b28a00dad507 100644
--- a/templates/overrides/menu/menu-local-tasks.html.twig
+++ b/templates/menu/menu-local-tasks.html.twig
@@ -15,15 +15,15 @@
 #}
 {% if primary %}
   <h2 class="visually-hidden">{{ 'Primary tabs'|t }}</h2>
-  {{ pattern('nav', {
+  {{ include('ui_suite_bootstrap:nav', {
     'variant': 'tabs',
-    'items': preprocessed_items_primary
-  }) }}
+    'items': preprocessed_items_primary,
+  }, with_context = false) }}
 {% endif %}
 {% if secondary %}
   <h2 class="visually-hidden">{{ 'Secondary tabs'|t }}</h2>
-  {{ pattern('nav', {
+  {{ include('ui_suite_bootstrap:nav', {
     'variant': 'tabs',
-    'items': preprocessed_items_secondary
-  }) }}
+    'items': preprocessed_items_secondary,
+  }, with_context = false) }}
 {% endif %}
diff --git a/templates/overrides/menu/menu.html.twig b/templates/menu/menu.html.twig
similarity index 89%
rename from templates/overrides/menu/menu.html.twig
rename to templates/menu/menu.html.twig
index 19db6c96bb9156b61c14580f47e90adeaacb814c..d4096b2c2f90fd73c92615439ea2f832e9a00907 100644
--- a/templates/overrides/menu/menu.html.twig
+++ b/templates/menu/menu.html.twig
@@ -19,8 +19,8 @@
  * Define a custom macro that will render all menu trees.
  */
 #}
-{{ pattern('navbar_nav', {
-  'variant': 'default',
-  'items': preprocessed_items,
+{{ include('ui_suite_bootstrap:navbar_nav', {
   'attributes': attributes.addClass(classes ?: ['menu', 'menu--' ~ menu_name|clean_class]),
-}) }}
+  'variant': 'default',
+  'items': items,
+}, with_context = false) }}
diff --git a/templates/overrides/node/node--bare.html.twig b/templates/node/node--bare.html.twig
similarity index 100%
rename from templates/overrides/node/node--bare.html.twig
rename to templates/node/node--bare.html.twig
diff --git a/templates/overrides/node/node.html.twig b/templates/node/node.html.twig
similarity index 100%
rename from templates/overrides/node/node.html.twig
rename to templates/node/node.html.twig
diff --git a/templates/overrides/commerce/cart/commerce-cart-empty-page.html.twig b/templates/overrides/commerce/cart/commerce-cart-empty-page.html.twig
deleted file mode 100644
index 29bf215e21df1586be3928a622d7c119ac8b99ec..0000000000000000000000000000000000000000
--- a/templates/overrides/commerce/cart/commerce-cart-empty-page.html.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-{#
-/**
- * @file
- *
- * Empty cart page template.
- *
- * @ingroup themeable
- */
-#}
-{{ pattern('alert', {
-  'variant': 'info',
-  'message': 'Your shopping cart is empty.'|t
-}) }}
diff --git a/templates/overrides/commerce/checkout/commerce-checkout-progress.html.twig b/templates/overrides/commerce/checkout/commerce-checkout-progress.html.twig
deleted file mode 100644
index a6a2df08a0b0f718df4c560af59a2729c0dbb73c..0000000000000000000000000000000000000000
--- a/templates/overrides/commerce/checkout/commerce-checkout-progress.html.twig
+++ /dev/null
@@ -1,46 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation for the checkout progress.
- *
- * Available variables:
- * - steps: An array of steps, where each step has the following keys:
- *   - id: The step ID.
- *   - label: The step label.
- *   - position: 'previous', 'current' or 'next'.
- *
- * @ingroup themeable
- */
-#}
-{# Prepare list group items. #}
-{% set items = [] %}
-{% for step in steps %}
-  {%
-    set list_group_item_classes = [
-    'checkout-progress--step',
-    'checkout-progress--step__' ~ step.position,
-    'flex-fill',
-  ]
-  %}
-  {% set list_group_item_attributes = create_attribute() %}
-  {% set items = items|merge([
-    pattern('list_group_item', {
-      'variant': 'primary',
-      'attributes': list_group_item_attributes.addClass(list_group_item_classes),
-      'content': step.label
-    })
-  ]) %}
-{% endfor %}
-
-{%
-  set list_group_classes = [
-  'checkout-progress',
-  'clearfix',
-]
-%}
-{% set list_group_attributes = create_attribute() %}
-{{ pattern('list_group', {
-  'variant': 'numbered__horizontal',
-  'attributes': list_group_attributes.addClass(list_group_classes),
-  'items': items
-}) }}
diff --git a/templates/overrides/ui_patterns_library/patterns-meta-information.html.twig b/templates/overrides/ui_patterns_library/patterns-meta-information.html.twig
deleted file mode 100644
index c2773182b399cbbf8474d23e1c3242cc706da2f2..0000000000000000000000000000000000000000
--- a/templates/overrides/ui_patterns_library/patterns-meta-information.html.twig
+++ /dev/null
@@ -1,82 +0,0 @@
-{#
-/**
- * @file
- * UI Pattern meta information.
- */
-#}
-
-{% if pattern is not empty %}
-
-  {# Pattern name and description. #}
-  <h3 class="pattern-preview__label display-3">{{ pattern.label }}</h3>
-  <p class="pattern-preview__description">{{ pattern.description }}</p>
-  {# External documentation links. #}
-  {% if pattern.render_links %}
-    <p>
-      {% for renderLink in pattern.render_links %}
-        {{ renderLink|add_class('btn btn-sm btn-primary') }}
-      {% endfor %}
-    </p>
-  {% endif %}
-
-  {% if pattern.tags %}
-    <p class="pattern-preview__tags">
-      {% for tag in pattern.tags %}
-        {{ pattern('badge', {
-          'label': tag,
-          'attributes': create_attribute({
-            'class': [
-              'text-bg-secondary'
-            ]
-          }),
-        }) }}
-      {% endfor %}
-    </p>
-  {% endif %}
-
-  {# Pattern fields descriptions. #}
-  {% if pattern.fields or pattern.additional.settings %}
-    <div class="table-responsive">
-      <table class="pattern-preview__fields table">
-        <thead>
-        <tr>
-          <th>{{ "Type"|t }}</th>
-          <th>{{ "Name"|t }}</th>
-          <th>{{ "Label"|t }}</th>
-          <th>{{ "Type"|t }}</th>
-          <th>{{ "Description"|t }} / {{ "Options"|t }}</th>
-        </tr>
-        </thead>
-        <tbody>
-        {% for field in pattern.fields %}
-          <tr>
-            <td>{{ "Field"|t }}</td>
-            <td><code>{{ field.name }}</code></td>
-            <td>{{ field.label }}</td>
-            <td><code>{{ field.type }}</code></td>
-            <td>{{ field.description }}</td>
-          </tr>
-        {% endfor %}
-        {% for name, setting in pattern.additional.settings %}
-          <tr>
-            <td>{{ "Setting"|t }}</td>
-            <td><code>{{ name }}</code></td>
-            <td>{{ setting.label }}</td>
-            <td><code>{{ setting.type }}</code></td>
-            <td>{{ setting.description }}
-              {% if setting.options %}
-                <ul>
-                  {% for key, label in setting.options %}
-                    <li>{{ key }}: {{ label }}</li>
-                  {% endfor %}
-                </ul>
-              {% endif %}
-            </td>
-          </tr>
-        {% endfor %}
-        </tbody>
-      </table>
-    </div>
-  {% endif %}
-
-{% endif %}
diff --git a/templates/overrides/ui_patterns_library/patterns-overview-page.html.twig b/templates/overrides/ui_patterns_library/patterns-overview-page.html.twig
deleted file mode 100644
index 42ad65c41dd2ec4c409a1764b45789cb95b40daf..0000000000000000000000000000000000000000
--- a/templates/overrides/ui_patterns_library/patterns-overview-page.html.twig
+++ /dev/null
@@ -1,63 +0,0 @@
-{#
-/**
- * @file
- * UI Pattern library page template, override this in your theme.
- */
-#}
-{% if patterns is not empty %}
-
-{% set content %}
-  <div id="patterns-library" class="overflow-auto">
-    {# List of available patterns with anchor links. #}
-    {% for group_name, group_patterns in patterns %}
-      {% if patterns|length > 1 %}
-        <h3>{{ group_name }}</h3>
-      {% endif %}
-      <ul class="nav nav-pills flex-column">
-        {% for pattern_name, pattern in group_patterns %}
-          <li class="nav-item">
-            <a href="#{{ pattern_name }}" class="nav-link p-1">{{ pattern.label }}</a>
-          </li>
-        {% endfor %}
-      </ul>
-    {% endfor %}
-  </div>
-{% endset %}
-
-<button class="btn btn-primary position-fixed bottom-0 end-0 mb-2 me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#menu-patterns" aria-controls="menu-patterns">
-  {{ 'Navigation'|t }}
-</button>
-{{ pattern('offcanvas', {
-  variant: 'start',
-  offcanvas_id: 'menu-patterns',
-  backdrop: 'false',
-  scroll: true,
-  heading_level: 2,
-  title: 'Available patterns'|t,
-  body: content
-}) }}
-
-<div class="row">
-  <div data-bs-spy="scroll" data-bs-target="#patterns-library" data-bs-smooth-scroll="true" tabindex="0" class="col col-12">
-    {% for group_name, group_patterns in patterns %}
-      {% for pattern_name, pattern in group_patterns %}
-        <div class="pattern-preview pattern-preview__{{ pattern.definition.id }}" id="{{ pattern_name }}">
-          {{ pattern.meta }}
-
-          {# Link to standalone pattern preview page.#}
-          <p class="my-3">
-            <a href="{{ url('ui_patterns.patterns.single', {'name': pattern_name}) }}" class="pattern-preview__view">
-              {% trans %}View {{ pattern.label }} as stand-alone{% endtrans %}
-            </a>
-          </p>
-
-          {# Rendered pattern preview. #}
-          {{ pattern.rendered }}
-        </div>
-
-        <hr class="my-5">
-      {% endfor %}
-    {% endfor %}
-  </div>
-</div>
-{% endif %}
diff --git a/templates/overrides/ui_patterns_library/patterns-single-page.html.twig b/templates/overrides/ui_patterns_library/patterns-single-page.html.twig
deleted file mode 100644
index f194962c554e598b1921c716723451fe21961205..0000000000000000000000000000000000000000
--- a/templates/overrides/ui_patterns_library/patterns-single-page.html.twig
+++ /dev/null
@@ -1,15 +0,0 @@
-{#
-/**
- * @file
- * UI Pattern library standalone page, override this in your theme.
- */
-#}
-
-{% if pattern is not empty %}
-  <div class="pattern-preview pattern-preview__{{ pattern.definition.id }} mb-5">
-    {{ pattern.meta }}
-
-    {# Rendered pattern preview. #}
-    {{ pattern.rendered }}
-  </div>
-{% endif %}
diff --git a/templates/overrides/ui_patterns_library/patterns-variant-meta-information.html.twig b/templates/overrides/ui_patterns_library/patterns-variant-meta-information.html.twig
deleted file mode 100644
index b5220829edca68ea3c87c3173bd6e0086f01a6cc..0000000000000000000000000000000000000000
--- a/templates/overrides/ui_patterns_library/patterns-variant-meta-information.html.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-{#
-/**
- * @file
- * UI Pattern variant meta information.
- */
-#}
-
-{% if variant is not empty %}
-<div class="my-3">
-  <h3>{{ variant.label }} (<code>{{ variant.name }}</code>)</h3>
-  {{ variant.description }}
-</div>
-{% endif %}
diff --git a/templates/overrides/paragraphs/paragraph--bare.html.twig b/templates/paragraphs/paragraph--bare.html.twig
similarity index 100%
rename from templates/overrides/paragraphs/paragraph--bare.html.twig
rename to templates/paragraphs/paragraph--bare.html.twig
diff --git a/templates/patterns/accordion/accordion.ui_patterns.yml b/templates/patterns/accordion/accordion.ui_patterns.yml
deleted file mode 100644
index 0eba5a3cbaf1f4227486c65e8497c9def4294db9..0000000000000000000000000000000000000000
--- a/templates/patterns/accordion/accordion.ui_patterns.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-accordion:
-  label: "Accordion"
-  description: "Render content in a box that expands and collapses vertically."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/accordion/'
-  category: "Accordion"
-  variants:
-    default:
-      label: "Default"
-    flush:
-      label: "Flush"
-      description: "Remove the default background color, some borders, and some rounded corners to render accordions edge-to-edge with their parent container."
-  settings:
-    keep_open:
-      type: "boolean"
-      label: "Keep open?"
-      description: "Make accordion items stay open when another item is opened."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    accordion_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-  fields:
-    content:
-      type: "list"
-      label: "Content"
-      description: "Accordion items."
-      preview:
-        - type: "pattern"
-          id: "accordion_item"
-          opened: true
-          fields:
-            title: "Accordion Item #1"
-            content:
-              type: "html_tag"
-              tag: "p"
-              value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
-        - type: "pattern"
-          id: "accordion_item"
-          opened: false
-          fields:
-            title: "Accordion Item #2"
-            content:
-              type: "html_tag"
-              tag: "p"
-              value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
-        - type: "pattern"
-          id: "accordion_item"
-          opened: false
-          fields:
-            title: "Accordion Item #3"
-            content:
-              type: "html_tag"
-              tag: "p"
-              value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
-        - type: "pattern"
-          id: "accordion_item"
-          opened: false
-          fields:
-            title: "Accordion Item #4"
-            content:
-              type: "html_tag"
-              tag: "p"
-              value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
-  libraries:
-    - accordion:
-        js:
-          js/accordion.js: {}
-        dependencies:
-          - core/drupal
-          - core/once
diff --git a/templates/patterns/accordion_item/accordion_item.ui_patterns.yml b/templates/patterns/accordion_item/accordion_item.ui_patterns.yml
deleted file mode 100644
index 8835a9a07ae0a5f2ccce1eb889170c60987a7936..0000000000000000000000000000000000000000
--- a/templates/patterns/accordion_item/accordion_item.ui_patterns.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-accordion_item:
-  label: "(Accordion item)"
-  description: "Internal: to be used in the 'Accordion' component."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/accordion'
-  category: "Accordion"
-  settings:
-    opened:
-      type: "boolean"
-      label: "Opened"
-      description: "If the accordion item is opened by default."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    heading_level:
-      type: "select"
-      label: "Heading level"
-      options:
-        2: "h2 (Default)"
-        3: "h3"
-        4: "h4"
-        5: "h5"
-        6: "h6"
-      preview: 2
-    item_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-  fields:
-    title:
-      type: "text"
-      label: "Title"
-      description: "Item title."
-      preview: "Item title"
-    content:
-      type: "render"
-      label: "Content"
-      description: "Accordion item content."
-      preview:
-        type: "html_tag"
-        tag: "p"
-        value: "Mollis pretium lorem primis senectus habitasse lectus scelerisque donec, ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque, consectetur mi risus molestie curae malesuada cum. Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes, mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus nibh est, metus lobortis morbi cras magna vivamus per risus fermentum."
diff --git a/templates/patterns/alert/alert.ui_patterns.yml b/templates/patterns/alert/alert.ui_patterns.yml
deleted file mode 100644
index ae3647793e6b90ac69bd0e1089fe0dd98821d9af..0000000000000000000000000000000000000000
--- a/templates/patterns/alert/alert.ui_patterns.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-alert:
-  label: "Alert"
-  description: "Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/alerts/'
-  variants:
-    primary:
-      label: "Primary"
-    secondary:
-      label: "Secondary"
-    success:
-      label: "Success"
-    danger:
-      label: "Danger"
-    warning:
-      label: "Warning"
-    info:
-      label: "Info"
-    light:
-      label: "Light"
-    dark:
-      label: "Dark"
-  settings:
-    dismissible:
-      type: "boolean"
-      label: "Dismissible?"
-      description: "It is possible to dismiss any alert inline."
-      preview: True
-      allow_expose: true
-      allow_token: true
-  fields:
-    heading:
-      type: "text"
-      label: "Heading"
-      description: "The alert heading. Optional."
-      preview: "Well done!"
-    message:
-      type: "render"
-      label: "Message"
-      description: "The alert message."
-      preview: "A simple alert. Check it out!"
-  libraries:
-    - alert:
-        css:
-          component:
-            styles/alert.css: {}
diff --git a/templates/patterns/badge/badge.ui_patterns.yml b/templates/patterns/badge/badge.ui_patterns.yml
deleted file mode 100644
index a8a7fe6477f93ad1d58c1620c2053e12cb33f56a..0000000000000000000000000000000000000000
--- a/templates/patterns/badge/badge.ui_patterns.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-badge:
-  label: "Badge"
-  description: "A small count and labeling component. Badges scale to match the size of the immediate parent element by using relative font sizing and em units."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/badge/'
-  fields:
-    label:
-      type: "text"
-      label: "Label"
-      description: "The badge's label."
-      preview: "New"
diff --git a/templates/patterns/badge/pattern-badge--preview.html.twig b/templates/patterns/badge/pattern-badge--preview.html.twig
deleted file mode 100644
index a2924d2c949b1cc93fae129c8d5bfba66bdcfa34..0000000000000000000000000000000000000000
--- a/templates/patterns/badge/pattern-badge--preview.html.twig
+++ /dev/null
@@ -1,2 +0,0 @@
-{% set attributes = attributes.addClass('text-bg-primary') %}
-{% extends 'pattern-badge.html.twig' %}
diff --git a/templates/patterns/blockquote/blockquote.ui_patterns.yml b/templates/patterns/blockquote/blockquote.ui_patterns.yml
deleted file mode 100644
index 18c67a24f40c03ad4f1ce4acdbf6b6cd292b5d62..0000000000000000000000000000000000000000
--- a/templates/patterns/blockquote/blockquote.ui_patterns.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-blockquote:
-  label: "Blockquote"
-  description: "For quoting blocks of content from another source within your document."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/content/typography/#blockquotes'
-  category: "Typography"
-  fields:
-    content:
-      type: "render"
-      label: "Content"
-      description: "The quote."
-      preview:
-        - type: "html_tag"
-          tag: "p"
-          value: "A well-known quote, contained in a blockquote element."
-    footer:
-      type: "render"
-      label: "Footer"
-      description: "For identifying the source. Wrap the name of the source work in <cite>."
-      preview:
-        - markup: "Someone famous in "
-        - type: "html_tag"
-          tag: "cite"
-          value: "Source Title"
-          attributes:
-            title: "Source Title"
diff --git a/templates/patterns/breadcrumb/breadcrumb.ui_patterns.yml b/templates/patterns/breadcrumb/breadcrumb.ui_patterns.yml
deleted file mode 100644
index df6000abb03c82b1a852c1a05c220386b619fc1d..0000000000000000000000000000000000000000
--- a/templates/patterns/breadcrumb/breadcrumb.ui_patterns.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-breadcrumb:
-  label: "Breadcrumb"
-  description: "Indicate the current page’s location within a navigational hierarchy that automatically adds separators via CSS."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/breadcrumb/'
-  category: "Navigation"
-  settings:
-    items:
-      type: links
-      label: Items
-      preview:
-        - title: Home
-          url: "#"
-        - title: Library
-          url: "#"
-        - title: Data
diff --git a/templates/patterns/button/button.ui_patterns.yml b/templates/patterns/button/button.ui_patterns.yml
deleted file mode 100644
index 5a690c0f65aef76c56fcf36966cdc7b9ce04c5d0..0000000000000000000000000000000000000000
--- a/templates/patterns/button/button.ui_patterns.yml
+++ /dev/null
@@ -1,138 +0,0 @@
-button:
-  label: "Button"
-  description: "For actions in forms, dialogs, and more with support for multiple sizes, states, and more."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/buttons/'
-  category: "Button"
-  variants:
-    default:
-      label: "Default"
-      description: "No 'btn' class added."
-    primary__sm:
-      label: "Primary small"
-    secondary__sm:
-      label: "Secondary small"
-    success__sm:
-      label: "Success small"
-    danger__sm:
-      label: "Danger small"
-    warning__sm:
-      label: "Warning small"
-    info__sm:
-      label: "Info small"
-    light__sm:
-      label: "Light small"
-    dark__sm:
-      label: "Dark small"
-    link__sm:
-      label: "Link small"
-    primary:
-      label: "Primary"
-    secondary:
-      label: "Secondary"
-    success:
-      label: "Success"
-    danger:
-      label: "Danger"
-    warning:
-      label: "Warning"
-    info:
-      label: "Info"
-    light:
-      label: "Light"
-    dark:
-      label: "Dark"
-    link:
-      label: "Link"
-    primary__lg:
-      label: "Primary large"
-    secondary__lg:
-      label: "Secondary large"
-    success__lg:
-      label: "Success large"
-    danger__lg:
-      label: "Danger large"
-    warning__lg:
-      label: "Warning large"
-    info__lg:
-      label: "Info large"
-    light__lg:
-      label: "Light large"
-    dark__lg:
-      label: "Dark large"
-    link__lg:
-      label: "Link large"
-    outline_primary__sm:
-      label: "Outline Primary small"
-    outline_secondary__sm:
-      label: "Outline Secondary small"
-    outline_success__sm:
-      label: "Outline Success small"
-    outline_danger__sm:
-      label: "Outline Danger small"
-    outline_warning__sm:
-      label: "Outline Warning small"
-    outline_info__sm:
-      label: "Outline Info small"
-    outline_light__sm:
-      label: "Outline Light small"
-    outline_dark__sm:
-      label: "Outline Dark small"
-    outline_primary:
-      label: "Outline Primary"
-    outline_secondary:
-      label: "Outline Secondary"
-    outline_success:
-      label: "Outline Success"
-    outline_danger:
-      label: "Outline Danger"
-    outline_warning:
-      label: "Outline Warning"
-    outline_info:
-      label: "Outline Info"
-    outline_light:
-      label: "Outline Light"
-    outline_dark:
-      label: "Outline Dark"
-    outline_primary__lg:
-      label: "Outline Primary large"
-    outline_secondary__lg:
-      label: "Outline Secondary large"
-    outline_success__lg:
-      label: "Outline Success large"
-    outline_danger__lg:
-      label: "Outline Danger large"
-    outline_warning__lg:
-      label: "Outline Warning large"
-    outline_info__lg:
-      label: "Outline Info large"
-    outline_light__lg:
-      label: "Outline Light large"
-    outline_dark__lg:
-      label: "Outline Dark large"
-  settings:
-    disabled:
-      type: "boolean"
-      label: "Disabled?"
-      description: "Is the button disabled?"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    label_visually_hidden:
-      type: "boolean"
-      label: "Hide button label?"
-      description: "Is the button's label hidden?"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    url:
-      type: "url"
-      label: "URL"
-      description: "The button URL. Optional."
-      preview: "https://example.com"
-  fields:
-    label:
-      type: "text"
-      label: "Label"
-      description: "The button label."
-      preview: "Submit"
diff --git a/templates/patterns/button_group/button_group.ui_patterns.yml b/templates/patterns/button_group/button_group.ui_patterns.yml
deleted file mode 100644
index cf507f3754b331c91053e4d1bf42e6dc43cee57a..0000000000000000000000000000000000000000
--- a/templates/patterns/button_group/button_group.ui_patterns.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-button_group:
-  label: "Button Group"
-  description: "Group a series of buttons together on a single line with the button group, and super-power them with JavaScript."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/button-group/'
-  category: "Button"
-  variants:
-    sm:
-      label: "Small"
-    default:
-      label: "Default"
-    lg:
-      label: "Large"
-    vertical:
-      label: "Vertical"
-      description: "Make a set of buttons appear vertically stacked rather than horizontally. Split button dropdowns are not supported here."
-  settings:
-    label:
-      type: "textfield"
-      label: "Role"
-      description: "The group label. Visually hidden. Used with assistive technologies."
-      preview: "Basic example"
-      allow_token: true
-  fields:
-    buttons:
-      type: "render"
-      label: "Buttons"
-      description: "An array of 'button' patterns."
-      preview:
-        - type: "pattern"
-          id: "button"
-          variant: "secondary"
-          fields:
-            label: "First"
-        - type: "pattern"
-          id: "button"
-          variant: "secondary"
-          fields:
-            label: "Second"
-        - type: "pattern"
-          id: "button"
-          variant: "secondary"
-          fields:
-            label: "Third"
diff --git a/templates/patterns/button_toolbar/button_toolbar.ui_patterns.yml b/templates/patterns/button_toolbar/button_toolbar.ui_patterns.yml
deleted file mode 100644
index 94b316f95b14dea196ba2662f2565c4971293fda..0000000000000000000000000000000000000000
--- a/templates/patterns/button_toolbar/button_toolbar.ui_patterns.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-button_toolbar:
-  label: "Button Toolbar"
-  description: "Combine sets of button groups into button toolbars for more complex components. Use utility classes as needed to space out groups, buttons, and more."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/button-group/#button-toolbar'
-  category: "Button"
-  settings:
-    label:
-      type: "textfield"
-      label: "Role"
-      description: "The toolbar label. Visually hidden. Used with assistive technologies."
-      preview: "Toolbar with button groups"
-      allow_token: true
-  fields:
-    groups:
-      type: "render"
-      label: "Groups"
-      description: "An array of 'button_group' patterns. Or other 'groupable' elements."
-      preview:
-        - type: "pattern_preview"
-          id: "button_group"
-          variant: "default"
-          attributes:
-            class:
-              - me-2
-        - type: "pattern_preview"
-          id: "button_group"
-          variant: "default"
-          attributes:
-            class:
-              - me-2
-        - type: "pattern_preview"
-          id: "button_group"
-          variant: "default"
diff --git a/templates/patterns/card/card.ui_patterns.yml b/templates/patterns/card/card.ui_patterns.yml
deleted file mode 100644
index cbc4e3f5691269aa89853e2a91b4474511e1296a..0000000000000000000000000000000000000000
--- a/templates/patterns/card/card.ui_patterns.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-card:
-  label: "Card"
-  description: "A card is a flexible and extensible content container. It includes options for headers and footers, a wide variety of content, contextual background colors, and powerful display options."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/card/'
-  category: "Card"
-  variants:
-    default:
-      label: "Default"
-    horizontal:
-      label: "Horizontal"
-  settings:
-    image_position:
-      type: "select"
-      label: "Image position"
-      description: "Only for default variant."
-      options:
-        top: "Top (Default)"
-        bottom: "Bottom"
-      preview: "top"
-      allow_expose: true
-      allow_token: true
-    image_col_classes:
-      type: "textfield"
-      label: "Image column classes"
-      description: "Only for horizontal variant. Default value: col-md-4"
-      default_value: "col-md-4"
-      preview: "col-md-4"
-      allow_expose: true
-      allow_token: true
-    content_col_classes:
-      type: "textfield"
-      label: "Content column classes"
-      description: "Only for horizontal variant. Default value: col-md-8"
-      default_value: "col-md-8"
-      preview: "col-md-8"
-      allow_expose: true
-      allow_token: true
-  fields:
-    image:
-      type: "render"
-      label: "Image"
-      description: "Card image."
-      preview:
-        theme: "image"
-        uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
-        alt: "&copy; 2017 John Smith photography"
-    header:
-      type: "render"
-      label: "Header"
-      description: "Card header."
-      preview: "Featured"
-    content:
-      type: "render"
-      label: "Content"
-      description: "Card body."
-      preview:
-        - type: "pattern"
-          id: "card_body"
-          fields:
-            title: "Card title"
-            subtitle: "Card subtitle"
-            text: "Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit."
-            content:
-              type: "pattern"
-              id: "button"
-              variant: "primary"
-              fields:
-                label: "Go somewhere"
-            links:
-              - type: "html_tag"
-                tag: "a"
-                value: "Card link"
-                attributes:
-                  href: "#"
-              - type: "html_tag"
-                tag: "a"
-                value: "Another link"
-                attributes:
-                  href: "#"
-    footer:
-      type: "render"
-      label: "Footer"
-      description: "Card footer."
-      preview:
-        type: "html_tag"
-        tag: "span"
-        value: "2 days ago"
diff --git a/templates/patterns/card/pattern-card--preview.html.twig b/templates/patterns/card/pattern-card--preview.html.twig
deleted file mode 100644
index 20bb6d7b7bc040967a6de14822f02ddeb13e513c..0000000000000000000000000000000000000000
--- a/templates/patterns/card/pattern-card--preview.html.twig
+++ /dev/null
@@ -1,6 +0,0 @@
-{% if variant and variant|lower == 'horizontal' %}
-  {% set header = '' %}
-  {% set footer = '' %}
-  {% set attributes = attributes.setAttribute('style', 'max-width: 540px;') %}
-{% endif %}
-{% extends 'pattern-card.html.twig' %}
diff --git a/templates/patterns/card_body/card_body.ui_patterns.yml b/templates/patterns/card_body/card_body.ui_patterns.yml
deleted file mode 100644
index 10f8895025a45913ce3235624bf2057aadd81e77..0000000000000000000000000000000000000000
--- a/templates/patterns/card_body/card_body.ui_patterns.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-card_body:
-  label: "(Card body)"
-  description: "Internal: to be used in the 'Card' component, because a card can have multiple 'Card body' components."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/card/'
-  category: "Card"
-  settings:
-    heading_level:
-      type: "select"
-      label: "Heading level"
-      options:
-        2: "h2"
-        3: "h3"
-        4: "h4"
-        5: "h5 (Default)"
-        6: "h6"
-      preview: 5
-      allow_expose: true
-      allow_token: true
-  fields:
-    title:
-      type: "text"
-      label: "Title"
-      description: "Card title. Plain text."
-      preview: "Card title"
-    subtitle:
-      type: "text"
-      label: "Subtitle"
-      description: "Card subtitle. Plain text."
-      preview: "Card subtitle"
-    text:
-      type: "text"
-      label: "Text"
-      description: "Card text. Plain text."
-      preview: "Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit."
-    content:
-      type: "render"
-      label: "Content"
-      description: "Free content outside of any wrapper."
-      preview:
-        type: "pattern"
-        id: "button"
-        variant: "primary"
-        fields:
-          label: "Go somewhere"
-    links:
-      type: "render"
-      label: "Links"
-      description: "Array of link elements"
-      preview:
-        - type: "html_tag"
-          tag: "a"
-          value: "Card link"
-          attributes:
-            href: "#"
-        - type: "html_tag"
-          tag: "a"
-          value: "Another link"
-          attributes:
-            href: "#"
diff --git a/templates/patterns/card_body/pattern-card-body--preview.html.twig b/templates/patterns/card_body/pattern-card-body--preview.html.twig
deleted file mode 100644
index 601bf46a42899e992d77cb65bfc45de832ef5f45..0000000000000000000000000000000000000000
--- a/templates/patterns/card_body/pattern-card-body--preview.html.twig
+++ /dev/null
@@ -1,9 +0,0 @@
-{#
-/**
- * For preview, to avoid warnings due to preview value transformed as markup
- * object.
- */
-#}
-<div class="card">
-  {{ include('pattern-card-body.html.twig') }}
-</div>
diff --git a/templates/patterns/card_group/card_group.ui_patterns.yml b/templates/patterns/card_group/card_group.ui_patterns.yml
deleted file mode 100644
index d00341da8027304a67df9fd6d8435424ec358d31..0000000000000000000000000000000000000000
--- a/templates/patterns/card_group/card_group.ui_patterns.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-card_group:
-  label: "Card group"
-  description: "Use card groups to render cards as a single, attached element with equal width and height columns. Card groups start off stacked and use display: flex; to become attached with uniform dimensions starting at the sm breakpoint. When using card groups with footers, their content will automatically line up."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/card/#card-groups'
-  category: "Card"
-  fields:
-    cards:
-      type: "render"
-      label: "Cards"
-      description: "An array of card patterns."
-      preview:
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
diff --git a/templates/patterns/card_layout/card_layout.ui_patterns.yml b/templates/patterns/card_layout/card_layout.ui_patterns.yml
deleted file mode 100644
index 0d0947f564e91abcaeba4f40c20e1f9a8bd0dbe7..0000000000000000000000000000000000000000
--- a/templates/patterns/card_layout/card_layout.ui_patterns.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-card_layout:
-  label: "Card Layout (deprecated)"
-  description: "Use the Card group pattern instead."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/card/#card-layout'
-  category: "Card"
-  fields:
-    cards:
-      type: "render"
-      label: "Cards"
-      description: "An array of card patterns."
-      preview:
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
diff --git a/templates/patterns/card_layout/pattern-card-layout.html.twig b/templates/patterns/card_layout/pattern-card-layout.html.twig
deleted file mode 100644
index ea43aad16eb124b15a11b0663e799a95558a8a0a..0000000000000000000000000000000000000000
--- a/templates/patterns/card_layout/pattern-card-layout.html.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-<div{{ attributes.addClass('card-group') }}>
-  {{ cards }}
-</div>
diff --git a/templates/patterns/card_overlay/card_overlay.ui_patterns.yml b/templates/patterns/card_overlay/card_overlay.ui_patterns.yml
deleted file mode 100644
index bcb33b29c92e178a30268a786211196a8489f37e..0000000000000000000000000000000000000000
--- a/templates/patterns/card_overlay/card_overlay.ui_patterns.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-card_overlay:
-  label: "Card overlay"
-  description: "Turn an image into a card background and overlay your card’s text. Depending on the image, you may or may not need additional styles or utilities."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/card/#image-overlays'
-  category: "Card"
-  settings:
-    heading_level:
-      type: "select"
-      label: "Heading level"
-      options:
-        2: "h2"
-        3: "h3"
-        4: "h4"
-        5: "h5 (Default)"
-        6: "h6"
-      preview: 5
-      allow_expose: true
-      allow_token: true
-  fields:
-    image:
-      type: "render"
-      label: "Image"
-      description: "Card image."
-      preview:
-        theme: "image"
-        uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
-        alt: "&copy; 2017 John Smith photography"
-    title:
-      type: "text"
-      label: "Title"
-      description: "Card title. Plain text."
-      preview: "Card title"
-    subtitle:
-      type: "text"
-      label: "Subtitle"
-      description: "Card subtitle. Plain text."
-      preview: "Card subtitle"
-    text:
-      type: "text"
-      label: "Text"
-      description: "Card text. Plain text."
-      preview: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer."
-    content:
-      type: "render"
-      label: "Content"
-      description: "Free content outside of any wrapper."
-      preview:
-        type: "html_tag"
-        tag: "p"
-        value: "<small>Last updated 3 mins ago</small>"
-        attributes:
-          class:
-            - "card-text"
-    links:
-      type: "render"
-      label: "Links"
-      description: "Array of link elements"
-      preview:
-        - type: "html_tag"
-          tag: "a"
-          value: "Card link"
-          attributes:
-            href: "#"
-        - type: "html_tag"
-          tag: "a"
-          value: "Another link"
-          attributes:
-            href: "#"
diff --git a/templates/patterns/card_overlay/pattern-card-overlay--preview.html.twig b/templates/patterns/card_overlay/pattern-card-overlay--preview.html.twig
deleted file mode 100644
index a7b10a5949023f0a96076e192b4f80bcc9c91206..0000000000000000000000000000000000000000
--- a/templates/patterns/card_overlay/pattern-card-overlay--preview.html.twig
+++ /dev/null
@@ -1,8 +0,0 @@
-{#
-/**
- * For preview, to avoid warnings due to preview value transformed as markup
- * object.
- */
-#}
-{% set attributes = attributes.addClass('text-bg-dark') %}
-{% extends 'pattern-card-overlay.html.twig' %}
diff --git a/templates/patterns/carousel/carousel.ui_patterns.yml b/templates/patterns/carousel/carousel.ui_patterns.yml
deleted file mode 100644
index 5d2262436e368adf757c7448bfc40c00a39c0b0c..0000000000000000000000000000000000000000
--- a/templates/patterns/carousel/carousel.ui_patterns.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-carousel:
-  label: "Carousel"
-  description: "A slideshow component for cycling through elements, like a carousel."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/carousel/'
-  category: "Carousel"
-  variants:
-    default:
-      label: "Default"
-    fade:
-      label: "Crossfade"
-      description: "Animate slides with a fade transition instead of a slide."
-    dark:
-      label: "Dark (deprecated)"
-      description: "For darker controls, indicators, and captions."
-    fade__dark:
-      label: "Crossfade dark (deprecated)"
-  settings:
-    with_controls:
-      type: "boolean"
-      label: "With controls?"
-      description: "Adding in the previous and next controls."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    with_indicators:
-      type: "boolean"
-      label: "With indicators?"
-      description: "You can also add the indicators to the carousel, alongside the controls, too."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    with_touch:
-      type: "boolean"
-      label: "With touch swiping?"
-      description: "Carousels support swiping left/right on touchscreen devices to move between slides."
-      default_value: true
-      allow_expose: true
-      allow_token: true
-    interval:
-      type: "number"
-      label: "Interval"
-      description: "The amount of time to delay between automatically cycling to the next item. In ms. 0 to disable autoplay."
-      default_value: 5000
-      allow_expose: true
-      allow_token: true
-    carousel_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-  fields:
-    slides:
-      type: "render"
-      label: "Slides"
-      description: "Each slide is a collection of carousel items."
-      preview:
-        - type: "pattern"
-          id: "carousel_item"
-          settings:
-            active: true
-          fields:
-            image:
-              theme: "image"
-              uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEZpcnN0IHNsaWRlIj48dGl0bGU+UGxhY2Vob2xkZXI8L3RpdGxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiM3NzciPjwvcmVjdD48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZmlsbD0iIzU1NSIgZHk9Ii4zZW0iPkZpcnN0IHNsaWRlPC90ZXh0Pjwvc3ZnPgo="
-            caption:
-              - type: "html_tag"
-                tag: "h5"
-                value: "First slide label"
-              - type: "html_tag"
-                tag: "p"
-                value: "Nulla vitae elit libero, a pharetra augue mollis interdum."
-        - type: "pattern"
-          id: "carousel_item"
-          settings:
-            interval: 10000
-          fields:
-            image:
-              theme: "image"
-              uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IFNlY29uZCBzbGlkZSI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjNjY2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiM0NDQiIGR5PSIuM2VtIj5TZWNvbmQgc2xpZGU8L3RleHQ+PC9zdmc+Cg=="
-            caption:
-              - type: "html_tag"
-                tag: "h5"
-                value: "Second slide label"
-              - type: "html_tag"
-                tag: "p"
-                value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
-        - type: "pattern"
-          id: "carousel_item"
-          fields:
-            image:
-              theme: "image"
-              uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IFRoaXJkIHNsaWRlIj48dGl0bGU+UGxhY2Vob2xkZXI8L3RpdGxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiM1NTUiPjwvcmVjdD48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZmlsbD0iIzMzMyIgZHk9Ii4zZW0iPlRoaXJkIHNsaWRlPC90ZXh0Pjwvc3ZnPgo="
-            caption:
-              - type: "html_tag"
-                tag: "h5"
-                value: "Third slide label"
-              - type: "html_tag"
-                tag: "p"
-                value: "Praesent commodo cursus magna, vel scelerisque nisl consectetur."
diff --git a/templates/patterns/carousel/pattern-carousel.html.twig b/templates/patterns/carousel/pattern-carousel.html.twig
deleted file mode 100644
index 046958c44acb2df10e50bc6476f6271cf154db4d..0000000000000000000000000000000000000000
--- a/templates/patterns/carousel/pattern-carousel.html.twig
+++ /dev/null
@@ -1,54 +0,0 @@
-{% if variant and variant|lower != 'default' %}
-  {% set variants = variant|split('__')|map(v => v|lower|replace({(v): 'carousel-' ~ v})|replace({'_': '-'})) %}
-  {% set attributes = attributes.addClass(variants) %}
-{% endif %}
-{% set attributes = 'dark' in variant|lower ? attributes.setAttribute('data-bs-theme', 'dark') : attributes %}
-
-{% if not with_touch %}
-  {% set attributes = attributes.setAttribute('data-bs-touch', 'false') %}
-{% endif %}
-
-{% set interval = interval|default(5000) %}
-{% set data_bs_ride = 'carousel' %}
-{% if interval == 0 %}
-  {% set interval = 'false' %}
-  {% set data_bs_ride = false %}
-{% endif %}
-{% set attributes = attributes.setAttribute('data-bs-interval', interval) %}
-{% set attributes = attributes.setAttribute('data-bs-ride', data_bs_ride) %}
-{% set carousel_id = carousel_id|default("carousel-" ~ random()) %}
-
-<div{{ attributes.addClass('carousel').addClass('slide').setAttribute('id', carousel_id) }}>
-
-  {% if with_indicators %}
-  <div class="carousel-indicators">
-    {% for slide in slides %}
-    <button type="button"
-            data-bs-target="#{{ carousel_id }}"
-            data-bs-slide-to="{{ loop.index0 }}"
-            aria-label="{{ 'Slide @slide_number'|t({'@slide_number': loop.index}) }}"
-      {% if loop.first %}
-      class="active"
-      aria-current="true"
-      {% endif %}>
-    </button>
-    {% endfor %}
-  </div>
-  {% endif %}
-
-  <div class="carousel-inner">
-    {{ slides }}
-  </div>
-
-  {% if with_controls %}
-  <button class="carousel-control-prev" type="button" data-bs-target="#{{ carousel_id }}" data-bs-slide="prev">
-    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
-    <span class="visually-hidden">{{ 'Previous'|t }}</span>
-  </button>
-  <button class="carousel-control-next" type="button" data-bs-target="#{{ carousel_id }}" data-bs-slide="next">
-    <span class="carousel-control-next-icon" aria-hidden="true"></span>
-    <span class="visually-hidden">{{ 'Next'|t }}</span>
-  </button>
-  {% endif %}
-
-</div>
diff --git a/templates/patterns/carousel_item/carousel_item.ui_patterns.yml b/templates/patterns/carousel_item/carousel_item.ui_patterns.yml
deleted file mode 100644
index e1364acb81cf1558eb2f87a647edd805b2662d83..0000000000000000000000000000000000000000
--- a/templates/patterns/carousel_item/carousel_item.ui_patterns.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-carousel_item:
-  label: "(Carousel Item)"
-  description: "Internal: to be used in the 'Carousel' component."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/carousel/'
-  category: "Carousel"
-  settings:
-    active:
-      type: "boolean"
-      label: "Active"
-      description: "If the carousel item is displayed."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    interval:
-      type: "number"
-      label: "Interval"
-      description: "The amount of time to delay between automatically cycling to the next item. In ms."
-      preview: 3000
-      allow_expose: true
-      allow_token: true
-  fields:
-    image:
-      type: "render"
-      label: "Image"
-      description: "The image of the item."
-      preview:
-        theme: "image"
-        uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAzLjVyZW07IHRleHQtYW5jaG9yOiBtaWRkbGU7IHVzZXItc2VsZWN0OiBub25lIiB3aWR0aD0iMTkyMCIgaGVpZ2h0PSI2NDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEZpcnN0IHNsaWRlIj48dGl0bGU+UGxhY2Vob2xkZXI8L3RpdGxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiM3NzciPjwvcmVjdD48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZmlsbD0iIzU1NSIgZHk9Ii4zZW0iPkZpcnN0IHNsaWRlPC90ZXh0Pjwvc3ZnPgo="
-    caption:
-      type: "render"
-      label: "Caption"
-      description: "The caption of the item."
-      preview:
-        - type: "html_tag"
-          tag: "h5"
-          value: "Slide label"
-        - type: "html_tag"
-          tag: "p"
-          value: "Nulla vitae elit libero, a pharetra augue mollis interdum."
diff --git a/templates/patterns/carousel_item/pattern-carousel-item--preview.html.twig b/templates/patterns/carousel_item/pattern-carousel-item--preview.html.twig
deleted file mode 100644
index ce437b73fc90381367d5afed9fa28f4b055758d0..0000000000000000000000000000000000000000
--- a/templates/patterns/carousel_item/pattern-carousel-item--preview.html.twig
+++ /dev/null
@@ -1,9 +0,0 @@
-<div class="row">
-  <div class="col">
-    <div class="carousel slide">
-      <div class="carousel-inner">
-        {{ include('pattern-carousel-item.html.twig') }}
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/templates/patterns/close_button/close_button.ui_patterns.yml b/templates/patterns/close_button/close_button.ui_patterns.yml
deleted file mode 100644
index f84b5ddf1245288a010a10b3857eee0e19e44ec3..0000000000000000000000000000000000000000
--- a/templates/patterns/close_button/close_button.ui_patterns.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-close_button:
-  label: "Close button"
-  description: "A generic close button for dismissing content like modals and alerts."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/close-button'
-  category: "Button"
-  variants:
-    default:
-      label: "Default"
-    white:
-      label: "White (deprecated)"
-  settings:
-    disabled:
-      type: "boolean"
-      label: "Disabled?"
-      description: "Is the button disabled?"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    aria_label:
-      type: "textfield"
-      label: "Aria label"
-      description: "Name of the close button for assistive technology."
-      preview: "Close"
-      allow_token: true
diff --git a/templates/patterns/close_button/pattern-close-button--preview.html.twig b/templates/patterns/close_button/pattern-close-button--preview.html.twig
deleted file mode 100644
index 478626197dd268d63865b4c5c1e27085b8f56735..0000000000000000000000000000000000000000
--- a/templates/patterns/close_button/pattern-close-button--preview.html.twig
+++ /dev/null
@@ -1,7 +0,0 @@
-{% if variant and variant|lower == 'white' %}
-  <div class="bg-dark">
-{% endif %}
-    {{ include('pattern-close-button.html.twig') }}
-{% if variant and variant|lower == 'white' %}
-  </div>
-{% endif %}
diff --git a/templates/patterns/figure/figure.ui_patterns.yml b/templates/patterns/figure/figure.ui_patterns.yml
deleted file mode 100644
index 2cfc0eaae9af70b8fed602bfc693aa316d7f4ccd..0000000000000000000000000000000000000000
--- a/templates/patterns/figure/figure.ui_patterns.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-figure:
-  label: "Figure"
-  description: "Used to display a piece of self-contained content (illustrations, diagrams, photos, code, etc) along with an optional caption. This content can be removed from the document without affecting the meaning of the document."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/content/figures/'
-  settings:
-    figcaption_attributes:
-      type: "attributes"
-      label: "Figcaption attributes"
-      description: "The attributes to customize the figcaption tag."
-      preview: 'class="text-end"'
-      allow_expose: true
-  fields:
-    image:
-      type: "render"
-      label: "Image"
-      description: "The content of the figure."
-      preview:
-        theme: "image"
-        uri: "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZm9udC1zaXplOiAxLjEyNXJlbTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgdXNlci1zZWxlY3Q6IG5vbmU7IiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIyNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgc2xpY2UiIGZvY3VzYWJsZT0iZmFsc2UiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iUGxhY2Vob2xkZXI6IEltYWdlIGNhcCI+PHRpdGxlPlBsYWNlaG9sZGVyPC90aXRsZT48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjODY4ZTk2Ij48L3JlY3Q+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZpbGw9IiNkZWUyZTYiIGR5PSIuM2VtIj5JbWFnZSBjYXA8L3RleHQ+PC9zdmc+Cg=="
-        alt: "&copy; 2017 John Smith photography"
-    caption:
-      type: "text"
-      label: "Caption"
-      description: "The caption that appears under the content."
-      preview: "A caption for the above image."
diff --git a/templates/patterns/grid_row/grid_row.ui_patterns.yml b/templates/patterns/grid_row/grid_row.ui_patterns.yml
deleted file mode 100644
index 255e085449b97bb26718f1b1f5b85908713e32f5..0000000000000000000000000000000000000000
--- a/templates/patterns/grid_row/grid_row.ui_patterns.yml
+++ /dev/null
@@ -1,202 +0,0 @@
-grid_row:
-  label: "Grid Row"
-  description: "The grid system uses a series of containers, rows, and columns to layout and align content  For simple use cases only. For more powerful needs, use bootstrap_grid_row_* layouts."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/layout/grid/'
-  category: "Layout"
-  settings:
-    with_container:
-      label: "With container?"
-      description: "Is the row wrapped in a container? Containers provide a means to center and horizontally pad your site’s contents."
-      type: "boolean"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    gutters:
-      label: "Gutters"
-      description: "The gutters between columns in our predefined grid classes can be removed with .no-gutters. This removes the negative margins from .row and the horizontal padding from all immediate children columns."
-      type: "select"
-      preview: "g-0"
-      options:
-        g-0: "0"
-        g-1: "1"
-        g-2: "2"
-        g-3: "3"
-        g-4: "4"
-        g-5: "5"
-      allow_expose: true
-      allow_token: true
-    gutters_horizontal:
-      label: "Horizontal gutters"
-      description: ".gx-* classes can be used to control the horizontal gutter widths. The .container or .container-fluid parent may need to be adjusted if larger gutters are used too to avoid unwanted overflow, using a matching padding utility."
-      type: "select"
-      preview: ""
-      options:
-        gx-0: "0"
-        gx-1: "1"
-        gx-2: "2"
-        gx-3: "3"
-        gx-4: "4"
-        gx-5: "5"
-      allow_expose: true
-      allow_token: true
-    gutters_vertical:
-      label: "Vertical gutters"
-      description: ".gy-* classes can be used to control the vertical gutter widths. Like the horizontal gutters, the vertical gutters can cause some overflow below the .row at the end of a page. If this occurs, you add a wrapper around .row with the .overflow-hidden class."
-      type: "select"
-      preview: ""
-      options:
-        gy-0: "0"
-        gy-1: "1"
-        gy-2: "2"
-        gy-3: "3"
-        gy-4: "4"
-        gy-5: "5"
-      allow_expose: true
-      allow_token: true
-    col_xs:
-      label: "All (Extra small)"
-      type: "select"
-      preview: ""
-      options:
-        col-1: "1"
-        col-2: "2"
-        col-3: "3"
-        col-4: "4"
-        col-5: "5"
-        col-6: "6"
-        col-7: "7"
-        col-8: "8"
-        col-9: "9"
-        col-10: "10"
-        col-11: "11"
-        col-12: "12"
-      allow_expose: true
-      allow_token: true
-    col_sm:
-      label: "Small"
-      type: "select"
-      preview: ""
-      options:
-        col-sm-1: "1"
-        col-sm-2: "2"
-        col-sm-3: "3"
-        col-sm-4: "4"
-        col-sm-5: "5"
-        col-sm-6: "6"
-        col-sm-7: "7"
-        col-sm-8: "8"
-        col-sm-9: "9"
-        col-sm-10: "10"
-        col-sm-11: "11"
-        col-sm-12: "12"
-      allow_expose: true
-      allow_token: true
-    col_md:
-      label: "Medium"
-      type: "select"
-      preview: "col-md-3"
-      options:
-        col-md-1: "1"
-        col-md-2: "2"
-        col-md-3: "3"
-        col-md-4: "4"
-        col-md-5: "5"
-        col-md-6: "6"
-        col-md-7: "7"
-        col-md-8: "8"
-        col-md-9: "9"
-        col-md-10: "10"
-        col-md-11: "11"
-        col-md-12: "12"
-      allow_expose: true
-      allow_token: true
-    col_lg:
-      label: "Large"
-      type: "select"
-      preview: ""
-      options:
-        col-lg-1: "1"
-        col-lg-2: "2"
-        col-lg-3: "3"
-        col-lg-4: "4"
-        col-lg-5: "5"
-        col-lg-6: "6"
-        col-lg-7: "7"
-        col-lg-8: "8"
-        col-lg-9: "9"
-        col-lg-10: "10"
-        col-lg-11: "11"
-        col-lg-12: "12"
-      allow_expose: true
-      allow_token: true
-    col_xl:
-      label: "Extra large"
-      type: "select"
-      preview: ""
-      options:
-        col-xl-1: "1"
-        col-xl-2: "2"
-        col-xl-3: "3"
-        col-xl-4: "4"
-        col-xl-5: "5"
-        col-xl-6: "6"
-        col-xl-7: "7"
-        col-xl-8: "8"
-        col-xl-9: "9"
-        col-xl-10: "10"
-        col-xl-11: "11"
-        col-xl-12: "12"
-      allow_expose: true
-      allow_token: true
-    col_xxl:
-      label: "Extra extra large"
-      type: "select"
-      preview: ""
-      options:
-        col-xxl-1: "1"
-        col-xxl-2: "2"
-        col-xxl-3: "3"
-        col-xxl-4: "4"
-        col-xxl-5: "5"
-        col-xxl-6: "6"
-        col-xxl-7: "7"
-        col-xxl-8: "8"
-        col-xxl-9: "9"
-        col-xxl-10: "10"
-        col-xxl-11: "11"
-        col-xxl-12: "12"
-      allow_expose: true
-      allow_token: true
-    spacing_margin_bottom:
-      label: "Cols margin bottom"
-      type: "select"
-      preview: ""
-      options:
-        mb-0: "0"
-        mb-1: "1"
-        mb-2: "2"
-        mb-3: "3"
-        mb-4: "4"
-        mb-5: "5"
-        mb-auto: "Auto"
-      allow_expose: true
-      allow_token: true
-  fields:
-    content:
-      type: "render"
-      label: "Content"
-      description: "The content of each column"
-      preview:
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
-        - type: "pattern_preview"
-          id: "card"
-          variant: "default"
diff --git a/templates/patterns/grid_row/pattern-grid-row.html.twig b/templates/patterns/grid_row/pattern-grid-row.html.twig
deleted file mode 100644
index 5b7ec9a09737ee1728005128b21a017fda001764..0000000000000000000000000000000000000000
--- a/templates/patterns/grid_row/pattern-grid-row.html.twig
+++ /dev/null
@@ -1,20 +0,0 @@
-{% if with_container %}
-  <div class="container">
-{% endif %}
-
-{% set attributes = gutters ? attributes.addClass(gutters) : attributes %}
-{% set attributes = gutters_horizontal ? attributes.addClass(gutters_horizontal) : attributes %}
-{% set attributes = gutters_vertical ? attributes.addClass(gutters_vertical) : attributes %}
-
-<div{{ attributes.addClass('row') }}>
-  {% for item in content %}
-    {% set col_sizes = [col_xs, col_sm, col_md, col_lg, col_xl, col_xxl, spacing_margin_bottom] %}
-    <div{{ create_attribute({'class': col_sizes}) }}>
-      {{ item }}
-    </div>
-  {% endfor %}
-</div>
-
-{% if with_container %}
-  </div>
-{% endif %}
diff --git a/templates/patterns/list/list.ui_patterns.yml b/templates/patterns/list/list.ui_patterns.yml
deleted file mode 100644
index 1cbaeb405f18ef189d43a3ef0e965ff6a836624b..0000000000000000000000000000000000000000
--- a/templates/patterns/list/list.ui_patterns.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-list:
-  label: "List"
-  links:
-    - "https://getbootstrap.com/docs/5.3/content/typography/#lists"
-  category: "Typography"
-  variants:
-    default:
-      label: "Default"
-    unstyled:
-      label: "Unstyled"
-      description: "Remove the default list-style and left margin on list items (immediate children only). This only applies to immediate children list items, meaning you will need to add the class for any nested lists as well."
-    inline:
-      label: "Inline"
-      description: "Remove a list’s bullets and apply some light margin with a combination of two classes, .list-inline and .list-inline-item."
-  settings:
-    list_type:
-      type: "select"
-      label: "List type"
-      options:
-        ul: "ul (Default)"
-        ol: "ol"
-      default: ul
-      preview: "ul"
-      allow_expose: true
-      allow_token: true
-  fields:
-    items:
-      type: "render"
-      label: "Items"
-      description: "An array of render arrays."
-      preview:
-        - type: "html_tag"
-          tag: "span"
-          value: "Lorem ipsum"
-        - type: "html_tag"
-          tag: "span"
-          value: "Phasellus iaculis"
-        - type: "html_tag"
-          tag: "span"
-          value: "Nulla volutpat"
diff --git a/templates/patterns/list_group/list_group.ui_patterns.yml b/templates/patterns/list_group/list_group.ui_patterns.yml
deleted file mode 100644
index ffba04e0c5cc89a878dcac7116f2ec4006ca0c62..0000000000000000000000000000000000000000
--- a/templates/patterns/list_group/list_group.ui_patterns.yml
+++ /dev/null
@@ -1,84 +0,0 @@
-list_group:
-  label: "List Group"
-  description: "List groups are a flexible and powerful component for displaying a series of content. Modify and extend them to support just about any content within."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/list-group/'
-  category: "List group"
-  variants:
-    default:
-      label: "Default"
-      description: "The most basic list group is an unordered list with list items and the proper classes. Build upon it with the options that follow, or with your own CSS as needed."
-    flush:
-      label: "Flush"
-      description: "Add .list-group-flush to remove some borders and rounded corners to render list group items edge-to-edge in a parent container (e.g., cards)."
-    numbered:
-      label: "Numbered"
-      description: "Add the .list-group-numbered modifier class (and optionally use an <ol> element) to opt into numbered list group items."
-    horizontal:
-      label: "Horizontal"
-      description: "Add .list-group-horizontal to change the layout of list group items from vertical to horizontal across all breakpoints. Currently horizontal list groups cannot be combined with flush list groups."
-    horizontal_sm:
-      label: "Horizontal Small"
-      description: "Horizontal starts at breakpoint small."
-    horizontal_md:
-      label: "Horizontal Medium"
-      description: "Horizontal starts at breakpoint medium."
-    horizontal_lg:
-      label: "Horizontal Large"
-      description: "Horizontal starts at breakpoint large."
-    horizontal_xl:
-      label: "Horizontal Extra large"
-      description: "Horizontal starts at breakpoint extra large."
-    horizontal_xxl:
-      label: "Horizontal Extra extra large"
-      description: "Horizontal starts at breakpoint extra extra large."
-    numbered__horizontal:
-      label: "Numbered Horizontal"
-      description: "Add the .list-group-numbered modifier class (and optionally use an <ol> element) to opt into numbered list group items. Add .list-group-horizontal to change the layout of list group items from vertical to horizontal across all breakpoints. Currently horizontal list groups cannot be combined with flush list groups."
-    numbered__horizontal_sm:
-      label: "Numbered Horizontal Small"
-      description: "Horizontal starts at breakpoint small."
-    numbered__horizontal_md:
-      label: "Numbered Horizontal Medium"
-      description: "Horizontal starts at breakpoint medium."
-    numbered__horizontal_lg:
-      label: "Numbered Horizontal Large"
-      description: "Horizontal starts at breakpoint large."
-    numbered__horizontal_xl:
-      label: "Numbered Horizontal Extra large"
-      description: "Horizontal starts at breakpoint extra large."
-    numbered__horizontal_xxl:
-      label: "Numbered Horizontal Extra extra large"
-      description: "Horizontal starts at breakpoint extra extra large."
-  fields:
-    items:
-      type: "render"
-      label: "Items"
-      description: "A list of List Group Items patterns."
-      preview:
-        - type: "pattern"
-          id: "list_group_item"
-          fields:
-            content: "The current link item"
-          settings:
-            active: true
-        - type: "pattern"
-          id: "list_group_item"
-          fields:
-            content: "A second link item"
-        - type: "pattern"
-          id: "list_group_item"
-          fields:
-            content: "A third link item"
-        - type: "pattern"
-          id: "list_group_item"
-          fields:
-            content: "A fourth link item, with a link"
-          settings:
-            url: "https://example.com"
-        - type: "pattern"
-          id: "list_group_item"
-          fields:
-            content: "The disabled link item"
-          settings:
-            disabled: true
diff --git a/templates/patterns/list_group_item/list_group_item.ui_patterns.yml b/templates/patterns/list_group_item/list_group_item.ui_patterns.yml
deleted file mode 100644
index 0e6669261220609a6bb8d1d88e8d863d8a3a2e9f..0000000000000000000000000000000000000000
--- a/templates/patterns/list_group_item/list_group_item.ui_patterns.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-list_group_item:
-  label: "(List Group Item)"
-  description: "Internal: to be used in the 'List Group' component."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/list-group/'
-  category: "List group"
-  variants:
-    default:
-      label: "Default"
-    primary:
-      label: "Primary"
-    secondary:
-      label: "Secondary"
-    success:
-      label: "Success"
-    danger:
-      label: "Danger"
-    warning:
-      label: "Warning"
-    info:
-      label: "Info"
-    light:
-      label: "Light"
-    dark:
-      label: "Dark"
-  settings:
-    active:
-      type: "boolean"
-      label: "Active?"
-      description: "Indicate the current active selection."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    disabled:
-      type: "boolean"
-      label: "Disabled?"
-      description: "Make it appears disabled. Note that some elements with .disabled will also require custom JavaScript to fully disable their click events (e.g., links)."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    url:
-      type: "url"
-      label: "URL"
-      description: "The button URL. Optional."
-  fields:
-    content:
-      type: "render"
-      label: "Content"
-      description: "Plain text, or any kind of content."
-      preview: "An item"
diff --git a/templates/patterns/modal/modal.ui_patterns.yml b/templates/patterns/modal/modal.ui_patterns.yml
deleted file mode 100644
index 21a038df2ed67bff7fd095c467a1938fa08b77cd..0000000000000000000000000000000000000000
--- a/templates/patterns/modal/modal.ui_patterns.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-modal:
-  label: "Modal"
-  description: "Use Bootstrap's JavaScript modal plugin to add dialogs to your site for lightboxes, user notifications, or completely custom content."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/modal/'
-  category: "Dialog"
-  variants:
-    sm:
-      label: "Small"
-    default:
-      label: "Default"
-    lg:
-      label: "Large"
-    xl:
-      label: "Extra large"
-  settings:
-    animation:
-      type: "boolean"
-      label: "Animation"
-      description: "For modals that simply appear rather than fade in to view."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    static:
-      type: "boolean"
-      label: "Static backdrop"
-      description: "When checked, the modal will not close when clicking outside of it."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    centered:
-      type: "boolean"
-      label: "Vertically centered"
-      description: "Vertically center the modal."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    scrollable:
-      type: "boolean"
-      label: "Scrollable"
-      description: "Allows to scroll the modal body."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    fullscreen:
-      type: "select"
-      label: "Fullscreen"
-      description: "Pop up a modal that covers the user viewport."
-      options:
-        modal-fullscreen: "Always"
-        modal-fullscreen-sm-down: "Below small"
-        modal-fullscreen-md-down: "Below medium"
-        modal-fullscreen-lg-down: "Below large"
-        modal-fullscreen-xl-down: "Below extra large"
-        modal-fullscreen-xxl-down: "Below extra extra large"
-    heading_level:
-      type: "select"
-      label: "Heading level"
-      description: "Heading level of the modal."
-      options:
-        1: "h1 (Default)"
-        2: "h2"
-        3: "h3"
-        4: "h4"
-        5: "h5"
-        6: "h6"
-      preview: 1
-    modal_id:
-      type: "textfield"
-      label: "ID"
-      description: "ID used by external buttons to toggle the visibility. Must start with a letter. Randomly generated if empty."
-  fields:
-    title:
-      type: "string"
-      label: "Title"
-      description: "Modal title."
-      preview: "Modal title"
-    body:
-      type: "render"
-      label: "Body"
-      description: "The content of the modal."
-      preview: "Modal body text goes here."
-    footer:
-      type: "render"
-      label: "Footer content"
-      description: "Footer content"
-      preview:
-        - type: "pattern"
-          id: "button"
-          variant: "secondary__sm"
-          fields:
-            label: "Close"
-          attributes:
-            data-bs-dismiss: "modal"
-        - type: "pattern"
-          id: "button"
-          variant: "primary__sm"
-          fields:
-            label: "Save changes"
diff --git a/templates/patterns/modal/pattern-modal--preview.html.twig b/templates/patterns/modal/pattern-modal--preview.html.twig
deleted file mode 100644
index dc3dffe2dbfb8f233b83dee424b3392e8a2e27c3..0000000000000000000000000000000000000000
--- a/templates/patterns/modal/pattern-modal--preview.html.twig
+++ /dev/null
@@ -1,12 +0,0 @@
-{% set modal_id = modal_id|default("modal-" ~ random()) %}
-
-{{ pattern('button', {
-  'variant': 'primary',
-  'label': 'Launch demo modal'|t,
-  'attributes': create_attribute({
-    'data-bs-target': '#' ~ modal_id,
-    'data-bs-toggle':'modal',
-  })
-}) }}
-
-{% include 'pattern-modal.html.twig' %}
diff --git a/templates/patterns/nav/nav.ui_patterns.yml b/templates/patterns/nav/nav.ui_patterns.yml
deleted file mode 100644
index a02fb83b0c1ab636ff2201b7fa8a6c289e3446c6..0000000000000000000000000000000000000000
--- a/templates/patterns/nav/nav.ui_patterns.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-nav:
-  label: "Nav"
-  description: "The base .nav component is built with flexbox and provide a strong foundation for building all types of navigation components. It includes some style overrides (for working with lists), some link padding for larger hit areas, and basic disabled styling."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/navs-tabs/'
-  category: "Navs and tabs"
-  variants:
-    default:
-      label: "Default"
-    tabs:
-      label: "Tabs"
-    tabs__fill:
-      label: "Tabs"
-    tabs__justified:
-      label: "Tabs"
-    pills:
-      label: "Pills"
-    pills__fill:
-      label: "Pills filled"
-    pills__justified:
-      label: "Pills filled with same width"
-    underline:
-      label: "Underline"
-  settings:
-    nav_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-    nav_type:
-      type: "select"
-      label: "List type"
-      options:
-        ul: "ul (Default)"
-        ol: "ol"
-        nav: "nav"
-      preview: "ul"
-      allow_expose: true
-      allow_token: true
-    card_header:
-      type: "boolean"
-      label: "Card header"
-      description: "Styling adjustment for tabs and pills variants when used in the header of the card component."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    items:
-      type: "links"
-      label: "Nav items"
-      preview:
-        - url: "#"
-          title: "Active"
-          link_attributes:
-            class:
-              - 'active'
-        - title: "Dropdown"
-          url: "#"
-          below:
-            - title: "Dropdown header"
-              link_attributes:
-                class: [dropdown-header]
-            - title: "Action"
-              url: '#'
-            - title: "Dropdown item text"
-            - title: "Another action"
-              url: '#'
-            - title: "Something else here"
-              url: '#'
-            - {}
-            - title: "Separated link"
-              url: '#'
-            - title: "Action (button)"
-              link_attributes:
-                class: [dropdown-item]
-            - title: "Another action (button)"
-              link_attributes:
-                class: [dropdown-item]
-            - title: "Something else here (text)"
-        - url: "#"
-          title: "Much longer nav link"
-        - url: "#"
-          title: "Disabled"
-          link_attributes:
-            class:
-              - 'disabled'
-  fields:
-    tab_content:
-      type: "render"
-      label: "Tab content"
-      description: "A list of renderable elements. Each item will be put in tab panes and the nav items will be used to navigate among the panes. You need to ensure that there is the same amount of nav links and tab items."
diff --git a/templates/patterns/navbar/navbar.ui_patterns.yml b/templates/patterns/navbar/navbar.ui_patterns.yml
deleted file mode 100644
index 66805bfed3f2f671d56b3c3fcfd811f0c033f98d..0000000000000000000000000000000000000000
--- a/templates/patterns/navbar/navbar.ui_patterns.yml
+++ /dev/null
@@ -1,116 +0,0 @@
-navbar:
-  label: "Navbar"
-  description: "Powerful, responsive navigation header, the navbar. Includes support for branding, navigation, and more, including support for our collapse plugin."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/navbar/'
-  category: "Navbar"
-  variants:
-    default:
-      label: "Default"
-    expand_sm:
-      label: "Expand small"
-    expand_md:
-      label: "Expand medium"
-    expand_lg:
-      label: "Expand large"
-    expand_xl:
-      label: "Expand extra large"
-    expand_xxl:
-      label: "Expand extra extra large"
-    dark:
-      label: "Dark (deprecated)"
-    dark__expand_sm:
-      label: "Dark expand small (deprecated)"
-    dark__expand_md:
-      label: "Dark expand medium (deprecated)"
-    dark__expand_lg:
-      label: "Dark expand large (deprecated)"
-    dark__expand_xl:
-      label: "Dark expand extra large (deprecated)"
-    dark__expand_xxl:
-      label: "Dark expand extra extra large (deprecated)"
-  settings:
-    navbar_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-    placement:
-      type: "select"
-      label: "Placement"
-      options:
-        default: "Default"
-        fixed-top: "Fixed top"
-        fixed-bottom: "Fixed bottom"
-        sticky-top: "Sticky top"
-        sticky-bottom: "Sticky bottom"
-      preview: "default"
-      allow_expose: true
-      allow_token: true
-    toggler_position:
-      type: "select"
-      label: "Toggler position"
-      description: "Navbar togglers are left-aligned by default, but should they follow a sibling element like a .navbar-brand, they’ll automatically be aligned to the far right. Reversing your markup will reverse the placement of the toggler"
-      options:
-        start: "Start"
-        end: "End"
-      preview: "end"
-      allow_expose: true
-      allow_token: true
-    toggle_action:
-      type: "select"
-      label: "Toggle action"
-      description: "Transform your expanding and collapsing navbar into an offcanvas drawer with the offcanvas plugin."
-      options:
-        collapse: "Collapse (default)"
-        offcanvas: "Offcanvas"
-      preview: "collapse"
-      allow_expose: true
-      allow_token: true
-    offcanvas_position:
-      type: "select"
-      label: "Offcanvas position"
-      options:
-        start: "Start"
-        end: "End (default)"
-      preview: "end"
-      allow_expose: true
-      allow_token: true
-  fields:
-    brand:
-      type: "render"
-      label: "Brand"
-      preview:
-        - theme: "image"
-          uri: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MTIiIGhlaWdodD0iNDA4Ij48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYSIgeDE9Ijc2LjA3OSIgeDI9IjUyMy40OCIgeTE9IjEwLjc5OCIgeTI9IjM2NS45NDUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjOTAxM2ZlIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjYxMGYyIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImJzLWxvZ28tYiIgeDE9IjE5My41MDgiIHgyPSIyOTMuNTE0IiB5MT0iMTA5Ljc0IiB5Mj0iMjc4Ljg3MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNmMWU1ZmMiLz48L2xpbmVhckdyYWRpZW50PjxmaWx0ZXIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBpZD0iYnMtbG9nby1jIiB3aWR0aD0iMTk3IiBoZWlnaHQ9IjI0OSIgeD0iMTYxLjkwMSIgeT0iODMuNDU3IiBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9InNSR0IiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz48ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiLz48ZmVPZmZzZXQgZHk9IjQiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI4Ii8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjE1IDAiLz48ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIHJlc3VsdD0ic2hhcGUiLz48L2ZpbHRlcj48L2RlZnM+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWEpIiBkPSJNNTYuNDgxIDUzLjMyQzU1LjUxNSAyNS41OCA3Ny4xMjggMCAxMDYuMzQyIDBoMjk5LjM1M2MyOS4yMTQgMCA1MC44MjcgMjUuNTggNDkuODYxIDUzLjMyLS45MjggMjYuNjQ3LjI3NyA2MS4xNjUgOC45NjQgODkuMzEgOC43MTUgMjguMjMyIDIzLjQxMSA0Ni4wNzcgNDcuNDggNDguMzd2MjZjLTI0LjA2OSAyLjI5My0zOC43NjUgMjAuMTM4LTQ3LjQ4IDQ4LjM3LTguNjg3IDI4LjE0NS05Ljg5MiA2Mi42NjMtOC45NjQgODkuMzExLjk2NiAyNy43MzktMjAuNjQ3IDUzLjMxOS00OS44NjEgNTMuMzE5SDEwNi4zNDJjLTI5LjIxNCAwLTUwLjgyNy0yNS41OC00OS44Ni01My4zMTkuOTI3LTI2LjY0OC0uMjc4LTYxLjE2Ni04Ljk2Ni04OS4zMTFDMzguODAyIDIzNy4xMzggMjQuMDcgMjE5LjI5MyAwIDIxN3YtMjZjMjQuMDY5LTIuMjkzIDM4LjgwMi0yMC4xMzggNDcuNTE2LTQ4LjM3IDguNjg4LTI4LjE0NSA5Ljg5My02Mi42NjMgOC45NjUtODkuMzF6Ii8+PHBhdGggZmlsbD0idXJsKCNicy1sb2dvLWIpIiBmaWx0ZXI9InVybCgjYnMtbG9nby1jKSIgc3Ryb2tlPSIjZmZmIiBkPSJNMjY3LjEwMyAzMTIuNDU3YzQ3LjI5NyAwIDc1Ljc5OC0yMy4xNTggNzUuNzk4LTYxLjM1NSAwLTI4Ljg3My0yMC4zMzYtNDkuNzc2LTUwLjUzMi01My4wODV2LTEuMjAzYzIyLjE4NS0zLjYwOSAzOS41OTQtMjQuMjExIDM5LjU5NC00Ny4yMTkgMC0zMi43ODMtMjUuODgyLTU0LjEzOC02NS4zMjItNTQuMTM4aC04OC43NHYyMTdoODkuMjAyem0tNTQuNjkyLTE4OS40OGg0NS45MTFjMjQuOTU4IDAgMzkuMTMxIDExLjEyOCAzOS4xMzEgMzEuMjc5IDAgMjEuNTA1LTE2LjQ4NCAzMy41MzUtNDYuMzcyIDMzLjUzNWgtMzguNjd2LTY0LjgxNHptMCAxNjEuOTYxdi03MS40MzFoNDUuNjAyYzMyLjY2MSAwIDQ5LjYwOCAxMi4wMyA0OS42MDggMzUuNDkgMCAyMy40NTktMTYuNDg0IDM1Ljk0MS00Ny42MDUgMzUuOTQxaC00Ny42MDV6Ii8+PC9zdmc+Cg=="
-          attributes:
-            width: "40px"
-            height: "32px"
-        - type: "html_tag"
-          tag: "a"
-          attributes:
-            href: "#"
-          value: "Brand"
-    navigation:
-      type: "render"
-      label: "Navigation"
-      description: "Navigation elements (brand, text, etc.) displayed even on small screens."
-      preview:
-        type: "html_tag"
-        tag: "span"
-        attributes:
-          class:
-            - navbar-text
-        value: "Text"
-    navigation_collapsible:
-      type: "render"
-      label: "Navigation collapsible"
-      description: "Navigation elements (menu links, etc.) displayed on collapsible dropdown on small screens."
-      preview:
-        type: "pattern_preview"
-        id: "navbar_nav"
-        variant: "default"
-    offcanvas_label:
-      type: "text"
-      label: "Offcanvas label"
-      description: "When using the offcanvas feature, used for labelling."
-      preview: "Offcanvas"
diff --git a/templates/patterns/navbar/pattern-navbar--preview.html.twig b/templates/patterns/navbar/pattern-navbar--preview.html.twig
deleted file mode 100644
index 48adf6939b5eeee8c94d698f99612261a227ae85..0000000000000000000000000000000000000000
--- a/templates/patterns/navbar/pattern-navbar--preview.html.twig
+++ /dev/null
@@ -1,7 +0,0 @@
-{% if 'dark' in variant|lower %}
-  {% set attributes = attributes.addClass('bg-dark') %}
-{% else %}
-  {% set attributes = attributes.addClass('bg-light') %}
-{% endif %}
-
-{% extends 'pattern-navbar.html.twig' %}
diff --git a/templates/patterns/navbar_nav/navbar_nav.ui_patterns.yml b/templates/patterns/navbar_nav/navbar_nav.ui_patterns.yml
deleted file mode 100644
index 6ad967b6025ecdb7c037b309c01a54ac5465e3f7..0000000000000000000000000000000000000000
--- a/templates/patterns/navbar_nav/navbar_nav.ui_patterns.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-navbar_nav:
-  label: "(Navbar nav)"
-  description: "Internal: to be used in the 'Navbar' component."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/navbar/'
-  category: "Navbar"
-  variants:
-    default:
-      label: "Default"
-    scroll:
-      label: "Scroll"
-  settings:
-    dropdown_id:
-      type: "textfield"
-      label: "ID"
-      description: "Must start with a letter. Randomly generated if empty."
-    items:
-      type: "links"
-      label: "Menu items"
-      description: "Full-height and lightweight navigation (including support for dropdowns)."
-      preview:
-        - title: "Home"
-          url: "https://example.com"
-        - title: "Library"
-          url: "https://example.com"
-          below:
-            - title: Dropdown header
-              link_attributes:
-                class: ["dropdown-header"]
-            - title: "Sub 1"
-              url: "https://example.com"
-            - {}
-            - title: "Sub 2 after divider"
-              url: "https://example.com"
-            - title: Dropdown text
-        - title: "Data"
diff --git a/templates/patterns/offcanvas/offcanvas.ui_patterns.yml b/templates/patterns/offcanvas/offcanvas.ui_patterns.yml
deleted file mode 100644
index 1e47ad3bf3cc80f70000d39ea64da72e6421db73..0000000000000000000000000000000000000000
--- a/templates/patterns/offcanvas/offcanvas.ui_patterns.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-offcanvas:
-  label: "Offcanvas"
-  description: "Build hidden sidebars into your project for navigation, shopping carts, and more with a few classes and our JavaScript plugin."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/offcanvas/'
-  category: "Dialog"
-  variants:
-    start:
-      label: "Start"
-    end:
-      label: "End"
-    top:
-      label: "Top"
-    bottom:
-      label: "Bottom"
-  settings:
-    responsive:
-      type: "select"
-      label: "Responsive"
-      description: "Hide content in offcanvas below the selected breakpoint. Above that breakpoint, the contents within will behave as usual."
-      options:
-        offcanvas-sm: "Hide below small"
-        offcanvas-md: "Hide below medium"
-        offcanvas-lg: "Hide below large"
-        offcanvas-xl: "Hide below extra large"
-        offcanvas-xxl: "Hide below extra extra large"
-      allow_expose: true
-      allow_token: true
-    backdrop:
-      type: "select"
-      label: "Backdrop"
-      description: "When backdrop is set to static, the offcanvas will not close when clicking outside of it."
-      options:
-        "false": "No backdrop"
-        static: "Static"
-      allow_expose: true
-      allow_token: true
-    scroll:
-      type: "boolean"
-      label: "Body scrolling"
-      description: "By default, body scrolling is disabled."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    heading_level:
-      type: "select"
-      label: "Heading level"
-      description: "Heading level of the offcanvas."
-      options:
-        1: "h1"
-        2: "h2"
-        3: "h3"
-        4: "h4"
-        5: "h5 (Default)"
-        6: "h6"
-      preview: 5
-    offcanvas_id:
-      type: "textfield"
-      label: "ID"
-      description: "ID used by external buttons to toggle the visibility. Must start with a letter. Randomly generated if empty."
-  fields:
-    title:
-      type: "string"
-      label: "Title"
-      description: "Offcanvas title."
-      preview: "Offcanvas"
-    body:
-      type: "render"
-      label: "Body"
-      description: "The content of the offcanvas."
-      preview: "Content for the offcanvas goes here. You can place just about any Bootstrap component or custom elements here."
diff --git a/templates/patterns/offcanvas/pattern-offcanvas--preview.html.twig b/templates/patterns/offcanvas/pattern-offcanvas--preview.html.twig
deleted file mode 100644
index 793941a6e3dd033fe663a503524ffe579aabf307..0000000000000000000000000000000000000000
--- a/templates/patterns/offcanvas/pattern-offcanvas--preview.html.twig
+++ /dev/null
@@ -1,14 +0,0 @@
-{% set offcanvas_id = offcanvas_id|default("offcanvas-" ~ random()) %}
-
-{{ pattern('button', {
-  variant: 'primary',
-  attributes: create_attribute({
-    'data-bs-target': '#' ~ offcanvas_id,
-    'data-bs-toggle': 'offcanvas',
-    'aria-controls': offcanvas_id,
-    'aria-expanded': 'false'
-  }),
-  label: 'Launch offcanvas'|t
-}) }}
-
-{% include 'pattern-offcanvas.html.twig' %}
diff --git a/templates/patterns/pagination/pagination.ui_patterns.yml b/templates/patterns/pagination/pagination.ui_patterns.yml
deleted file mode 100644
index 1a675952bb1f2f9a8d059c7953c4662198d877f9..0000000000000000000000000000000000000000
--- a/templates/patterns/pagination/pagination.ui_patterns.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-pagination:
-  label: "Pagination"
-  description: "Indicate a series of related content exists across multiple pages."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/pagination/'
-  category: "Navigation"
-  variants:
-    sm:
-      label: "Smaller"
-    default:
-      label: "Default"
-    lg:
-      label: "Larger"
-  settings:
-    items:
-      type: links
-      label: Pagination items
-      preview:
-        - url: "#"
-          title: "« First"
-        - url: "#"
-          title: "‹ Previous"
-        - title: "4"
-        - url: "#"
-          title: "5"
-        - url: "#"
-          title: "6"
-        - url: "#"
-          title: "Next ›"
-        - url: "#"
-          title: "Last »"
diff --git a/templates/patterns/progress/progress.ui_patterns.yml b/templates/patterns/progress/progress.ui_patterns.yml
deleted file mode 100644
index 0a26b2bfe06e039eeb4edb00d1c5f59d073fb850..0000000000000000000000000000000000000000
--- a/templates/patterns/progress/progress.ui_patterns.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-progress:
-  label: "Progress"
-  description: "The progress element displays an indicator showing the completion progress of a task, typically in the form of a bar. Progress components are built with two HTML elements, some CSS to set the width, and a few attributes. Bootstrap does not use the HTML5 <progress> element, ensuring you can stack progress bars, animate them, and place text labels over them."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/progress/'
-  category: "Progress"
-  variants:
-    default:
-      label: "Default"
-    striped:
-      label: "Striped"
-    striped__animated:
-      label: "Animated stripes"
-  settings:
-    aria_label:
-      type: "textfield"
-      label: "Aria label"
-      description: "Name of the progress bar for assistive technology."
-      allow_token: true
-    percent:
-      type: "number"
-      label: "Total progress (%)"
-      description: "Width of the progress element representing total progress (25%, 50%, etc.)."
-      allow_token: true
-      preview: 50
-    min:
-      type: "number"
-      label: "Minimum value"
-      description: "Minimum value of the progress element (default is 0). Used for an aria attribute."
-      allow_token: true
-      preview: 0
-    max:
-      type: "number"
-      label: "Maximum value"
-      description: "Maximum value of the progress element (default is 100). Used for an aria attribute."
-      allow_token: true
-      preview: 100
-    bar_height:
-      type: "number"
-      label: "Height"
-      description: "Height of progress element in pixels (px). Leave empty for default height."
-      allow_token: true
-    stacked:
-      type: "boolean"
-      label: "Stacked"
-      description: "If the progress is stacked with others."
-      preview: false
-      allow_expose: true
-      allow_token: true
-  fields:
-    label:
-      type: "text"
-      label: "Label"
-      description: "Text shown inside the progress bar."
-      preview: "Label"
diff --git a/templates/patterns/progress_stacked/progress_stacked.ui_patterns.yml b/templates/patterns/progress_stacked/progress_stacked.ui_patterns.yml
deleted file mode 100644
index 4040b0c8f444c1ac2d0a6b7c1872811e35f26085..0000000000000000000000000000000000000000
--- a/templates/patterns/progress_stacked/progress_stacked.ui_patterns.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-progress_stacked:
-  label: "Progress stacked"
-  description: "You can include multiple progress components inside a container with .progress-stacked to create a single stacked progress bar. Note that in this case, the styling to set the visual width of the progress bar must be applied to the .progress elements, rather than the .progress-bars."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/progress/#multiple-bars'
-  category: "Progress"
-  fields:
-    items:
-      type: "render"
-      label: "Progress bars"
-      description: "The progress bars to stack."
-      preview:
-        - type: "pattern"
-          id: "progress"
-          aria_label: "Segment one"
-          percent: 15
-          min: 0
-          max: 100
-          stacked: true
-        - type: "pattern"
-          id: "progress"
-          aria_label: "Segment two"
-          percent: 30
-          min: 0
-          max: 100
-          stacked: true
-          attributes:
-            class:
-              - "bg-success"
-        - type: "pattern"
-          id: "progress"
-          aria_label: "Segment three"
-          percent: 20
-          min: 0
-          max: 100
-          stacked: true
-          attributes:
-            class:
-              - "bg-info"
diff --git a/templates/patterns/spinner/spinner.ui_patterns.yml b/templates/patterns/spinner/spinner.ui_patterns.yml
deleted file mode 100644
index b9972c900f7ab21abc8da73bc2bd0d0affb16d6e..0000000000000000000000000000000000000000
--- a/templates/patterns/spinner/spinner.ui_patterns.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-spinner:
-  label: "Spinner"
-  description: "Indicate the loading state of a component or page with Bootstrap spinners, built entirely with HTML, CSS, and no JavaScript."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/spinners'
-  variants:
-    border__border_sm:
-      label: "Border small"
-    border:
-      label: "Border"
-    grow__grow_sm:
-      label: "Growing small"
-    grow:
-      label: "Growing"
-  settings:
-    aria_hidden:
-      type: "boolean"
-      label: "Aria hidden"
-      description: "Hide the spinner for assistive technology. When a label is also present outside of the spinner."
-      preview: false
-      allow_expose: true
-      allow_token: true
-    visually_hidden_label:
-      type: "textfield"
-      label: "Visually hidden label"
-      description: "A visually hidden label if the spinner is used as standalone."
-      preview: 'Loading...'
-      allow_expose: true
-      allow_token: true
diff --git a/templates/patterns/table/table.ui_patterns.yml b/templates/patterns/table/table.ui_patterns.yml
deleted file mode 100644
index de319d2928d3d5393cdcc332bbb983b9589d12bb..0000000000000000000000000000000000000000
--- a/templates/patterns/table/table.ui_patterns.yml
+++ /dev/null
@@ -1,860 +0,0 @@
-table:
-  label: "Table"
-  description: "Due to the widespread use of <table> elements across third-party widgets like calendars and date pickers, Bootstrap’s tables are opt-in. Add the base class .table to any <table>, then extend with our optional modifier classes or custom styles. All table styles are not inherited in Bootstrap, meaning any nested tables can be styled independent from the parent."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/content/tables/'
-  category: "Table"
-  variants:
-    default:
-      label: "Default"
-    sm:
-      label: "Small"
-    primary:
-      label: "Primary"
-    secondary:
-      label: "Secondary"
-    success:
-      label: "Success"
-    danger:
-      label: "Danger"
-    warning:
-      label: "Warning"
-    info:
-      label: "Info"
-    light:
-      label: "Light"
-    dark:
-      label: "Dark"
-    primary__sm:
-      label: "Primary small"
-    secondary__sm:
-      label: "Secondary small"
-    success__sm:
-      label: "Success small"
-    danger__sm:
-      label: "Danger small"
-    warning__sm:
-      label: "Warning small"
-    info__sm:
-      label: "Info small"
-    light__sm:
-      label: "Light small"
-    dark__sm:
-      label: "Dark small"
-  settings:
-    header_color:
-      type: "select"
-      label: "Table header color"
-      options:
-        primary: "Primary"
-        secondary: "Secondary"
-        success: "Success"
-        danger: "Danger"
-        warning: "Warning"
-        info: "Info"
-        light: "Light"
-        dark: "Dark"
-      preview: "light"
-      allow_expose: true
-      allow_token: true
-    footer_color:
-      type: "select"
-      label: "Table footer color"
-      options:
-        primary: "Primary"
-        secondary: "Secondary"
-        success: "Success"
-        danger: "Danger"
-        warning: "Warning"
-        info: "Info"
-        light: "light"
-        dark: "Dark"
-      allow_expose: true
-      allow_token: true
-    stripes:
-      type: "checkboxes"
-      label: "Striped table"
-      description: "Add zebra-striping to either the rows and/or the columns of the table."
-      options:
-        striped: "Striped rows"
-        striped-columns: "Striped columns"
-      preview:
-        - "striped"
-      allow_expose: true
-      allow_token: true
-    borders:
-      type: "select"
-      label: "Table border style"
-      description: "By default, rows have borders, but not the table itself or the columns. The 'borders' option adds borders on all sides of the table and cells. 'Borderless' removes all borders."
-      options:
-        bordered: "With borders"
-        borderless: "Borderless"
-      allow_expose: true
-      allow_token: true
-    hover:
-      type: "boolean"
-      label: "Hoverable rows"
-      description: "Enable a hover state when passing the mouse over a row."
-      preview: true
-      allow_expose: true
-      allow_token: true
-    divider:
-      type: "checkboxes"
-      label: "Table group divider"
-      description: "Add a thicker, darker border between table groups."
-      options:
-        thead: "Header"
-        tbody: "Body"
-        tfoot: "Footer"
-      preview:
-        - "tbody"
-      allow_expose: true
-      allow_token: true
-    responsive:
-      type: "select"
-      label: "Responsive"
-      description: "Responsive tables allow tables to be scrolled horizontally with ease."
-      options:
-        responsive: "Always responsive"
-        responsive-sm: "Responsive below small"
-        responsive-md: "Responsive below medium"
-        responsive-lg: "Responsive below large"
-        responsive-xl: "Responsive below extra large"
-        responsive-xxl: "Responsive below extra extra large"
-      preview: "responsive"
-      allow_expose: true
-      allow_token: true
-    caption_top:
-      type: "boolean"
-      label: "Caption top"
-      description: "Display caption at top of the table."
-      allow_expose: true
-      allow_token: true
-    header_columns:
-      type: "number"
-      label: "Number of columns in the header"
-      description: "Used to display properly the empty message if the table is empty. Leave empty for automatic value."
-      allow_expose: true
-      allow_token: true
-  fields:
-    colgroups:
-      type: "List"
-      label: "Colgroups"
-      description: "Sticked to Drupal structure after preprocessing of the Drupal table element."
-    header:
-      type: "Render"
-      label: "Header"
-      description: "A sequence of cell components."
-      preview:
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          active: true
-          content: "Table head (active)"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-        - type: "pattern"
-          id: "table_cell"
-          tag: "th"
-          content: "Table head"
-    rows:
-      type: "Render"
-      label: "Rows"
-      description: "A sequence of row components."
-      preview:
-        - type: "pattern"
-          id: "table_row"
-          color: "success"
-          fields:
-            cells:
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 1"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 2"
-              - type: "pattern"
-                id: "table_cell"
-                active: true
-                content: "Cell 3"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 4"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 5"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 6"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 7"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 8"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 9"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 10"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 11"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 12"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 13"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 14"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 15"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 16"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 17"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 18"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 19"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 20"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 21"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 22"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 23"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 24"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 25"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 26"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 27"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 28"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 29"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 30"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 31"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 32"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 33"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 34"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 35"
-        - type: "pattern"
-          id: "table_row"
-          color: "warning"
-          fields:
-            cells:
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 1"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 2"
-              - type: "pattern"
-                id: "table_cell"
-                active: true
-                content: "Cell 3"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 4"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 5"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 6"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 7"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 8"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 9"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 10"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 11"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 12"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 13"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 14"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 15"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 16"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 17"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 18"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 19"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 20"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 21"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 22"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 23"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 24"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 25"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 26"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 27"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 28"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 29"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 30"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 31"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 32"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 33"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 34"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 35"
-        - type: "pattern"
-          id: "table_row"
-          fields:
-            cells:
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 1"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 2"
-              - type: "pattern"
-                id: "table_cell"
-                active: true
-                content: "Cell 3"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 4"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 5"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 6"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 7"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 8"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 9"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 10"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 11"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 12"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 13"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 14"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 15"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 16"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 17"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 18"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 19"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 20"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 21"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 22"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 23"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 24"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 25"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 26"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 27"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 28"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 29"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 30"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 31"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 32"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 33"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 34"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 35"
-        - type: "pattern"
-          id: "table_row"
-          fields:
-            cells:
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 1"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 2"
-              - type: "pattern"
-                id: "table_cell"
-                active: true
-                content: "Cell 3"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 4"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 5"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 6"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 7"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 8"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 9"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 10"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 11"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 12"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 13"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 14"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 15"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 16"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 17"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 18"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 19"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 20"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 21"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 22"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 23"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 24"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 25"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 26"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 27"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 28"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 29"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 30"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 31"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 32"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 33"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 34"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Cell 35"
-    footer:
-      type: "Render"
-      label: "Footer"
-      description: "A sequence of row components."
-      preview:
-        - type: "pattern"
-          id: "table_row"
-          fields:
-            cells:
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                active: true
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-              - type: "pattern"
-                id: "table_cell"
-                content: "Footer"
-    empty:
-      type: "Render"
-      label: "Empty"
-      description: "Render element used when there is no rows."
-    caption:
-      type: "text"
-      label: "Caption"
-      description: "A caption functions like a heading for a table. It helps users with screen readers to find a table and understand what it's about and decide if they want to read it. By default it is displayed at the bottom of the table."
-      preview: "Example table (caption)"
diff --git a/templates/patterns/table_cell/table_cell.ui_patterns.yml b/templates/patterns/table_cell/table_cell.ui_patterns.yml
deleted file mode 100644
index 2f2e7ca5c596ac5b2c2a3485960fd3bd759dbf95..0000000000000000000000000000000000000000
--- a/templates/patterns/table_cell/table_cell.ui_patterns.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-table_cell:
-  label: "(Table Cell)"
-  description: "Internal: to be used in the 'Table' and 'Table Row' components."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/content/tables/'
-  category: "Table"
-  settings:
-    tag:
-      type: "select"
-      label: "HTML tag"
-      options:
-        th: "Head"
-        td: "Data (default)"
-      preview: "td"
-      allow_expose: true
-      allow_token: true
-    color:
-      type: "select"
-      label: "Cell color"
-      options:
-        primary: "Primary"
-        secondary: "Secondary"
-        success: "Success"
-        danger: "Danger"
-        warning: "Warning"
-        info: "Info"
-        light: "Light"
-        dark: "Dark"
-      preview: ""
-      allow_expose: true
-      allow_token: true
-    active:
-      type: "boolean"
-      label: "Active"
-      description: "Active state"
-      preview: false
-      allow_expose: true
-      allow_token: true
-  fields:
-    content:
-      type: "Render"
-      label: "Cell content"
-      description: "The cell content."
-      preview: "Cell content"
diff --git a/templates/patterns/table_row/table_row.ui_patterns.yml b/templates/patterns/table_row/table_row.ui_patterns.yml
deleted file mode 100644
index a807c8d1d9710fb79dfaa23be7f416aa0e2bf12c..0000000000000000000000000000000000000000
--- a/templates/patterns/table_row/table_row.ui_patterns.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-table_row:
-  label: "(Table Row)"
-  description: "Internal: to be used in the 'Table' component."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/content/tables/'
-  category: "Table"
-  settings:
-    color:
-      type: "select"
-      label: "Row color"
-      options:
-        primary: "Primary"
-        secondary: "Secondary"
-        success: "Success"
-        danger: "Danger"
-        warning: "Warning"
-        info: "Info"
-        light: "Light"
-        dark: "Dark"
-      preview: ""
-      allow_expose: true
-      allow_token: true
-    active:
-      type: "boolean"
-      label: "Active"
-      description: "Active state"
-      preview: false
-      allow_expose: true
-      allow_token: true
-  fields:
-    cells:
-      type: "Render"
-      label: "Row cells"
-      description: "A sequence of cell components."
diff --git a/templates/patterns/toast/pattern-toast--preview.html.twig b/templates/patterns/toast/pattern-toast--preview.html.twig
deleted file mode 100644
index 00f540f4e52b6c0a21af69b8f312f13692ecbf91..0000000000000000000000000000000000000000
--- a/templates/patterns/toast/pattern-toast--preview.html.twig
+++ /dev/null
@@ -1,4 +0,0 @@
-<div class="toast-container position-static">
-  {% set attributes = attributes.addClass('show') %}
-  {% include 'pattern-toast.html.twig' %}
-</div>
diff --git a/templates/patterns/toast/toast.ui_patterns.yml b/templates/patterns/toast/toast.ui_patterns.yml
deleted file mode 100644
index 6b38bf4f6b76e51ead45858a2328976588a52bb8..0000000000000000000000000000000000000000
--- a/templates/patterns/toast/toast.ui_patterns.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-toast:
-  label: "Toast"
-  description: "Push notifications to your visitors with a toast, a lightweight and easily customizable alert message."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/toast/'
-  category: "Toast"
-  settings:
-    delay:
-      type: "number"
-      label: "Hide delay"
-      description: "The duration before automatically hide the toast. In ms. 0 to disable the automatic hide."
-      default_value: 5000
-      allow_expose: true
-      allow_token: true
-    role:
-      type: "select"
-      label: "Role"
-      description: "Adapt the role level depending on the content. If it’s an important message like an error, use alert, otherwise use status."
-      options:
-        alert: "Alert (Default)"
-        status: "Status"
-        log: "Log"
-      preview: "alert"
-      allow_expose: true
-      allow_token: true
-    flex_wrapper:
-      type: "boolean"
-      label: "Add inside flex wrapper"
-      description: "Add a flex wrapper inside the toast, see https://getbootstrap.com/docs/5.3/components/toasts/#custom-content. Default: false"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    hide_close_button:
-      type: "boolean"
-      label: "Hide close button"
-      description: "If checked, you will have to provide a close button in another way. Default: false"
-      preview: false
-      allow_expose: true
-      allow_token: true
-    close_button_variant:
-      type: "select"
-      label: "Close button variant"
-      options:
-        default: "Default (Default)"
-        white: "White"
-      preview: "default"
-      allow_expose: true
-      allow_token: true
-  fields:
-    header:
-      type: "render"
-      label: "Header"
-      description: "Toast header."
-      preview:
-        - theme: "image"
-          uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
-          attributes:
-            class:
-              - "rounded"
-              - "me-2"
-        - type: "html_tag"
-          tag: "strong"
-          value: "Bootstrap"
-          attributes:
-            class:
-              - "me-auto"
-        - type: "html_tag"
-          tag: "small"
-          value: "11 mins ago"
-    content:
-      type: "render"
-      label: "Content toast"
-      description: "The toast item content."
-      preview: "Hello, world! This is a toast message."
diff --git a/templates/patterns/toast_container/pattern-toast-container--preview.html.twig b/templates/patterns/toast_container/pattern-toast-container--preview.html.twig
deleted file mode 100644
index 22558b190782583ba905fc2900cba56c15fb69a8..0000000000000000000000000000000000000000
--- a/templates/patterns/toast_container/pattern-toast-container--preview.html.twig
+++ /dev/null
@@ -1,2 +0,0 @@
-{% set attributes = attributes.addClass('position-static') %}
-{% extends 'pattern-toast-container.html.twig' %}
diff --git a/templates/patterns/toast_container/toast_container.ui_patterns.yml b/templates/patterns/toast_container/toast_container.ui_patterns.yml
deleted file mode 100644
index 3e3ae79554f3511bd1a40a73882163515618eff9..0000000000000000000000000000000000000000
--- a/templates/patterns/toast_container/toast_container.ui_patterns.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-toast_container:
-  label: "Toast container"
-  description: "You can stack toasts by wrapping them in a toast container, which will vertically add some spacing."
-  links:
-    - 'https://getbootstrap.com/docs/5.3/components/toasts/#stacking'
-  category: "Toast"
-  fields:
-    items:
-      type: "render"
-      label: "Toast items"
-      preview:
-        - type: "pattern"
-          id: "toast"
-          attributes:
-            class:
-              - "show"
-          header:
-            - theme: "image"
-              uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
-              attributes:
-                class:
-                  - "rounded"
-                  - "me-2"
-            - type: "html_tag"
-              tag: "strong"
-              value: "Bootstrap"
-              attributes:
-                class:
-                  - "me-auto"
-            - type: "html_tag"
-              tag: "small"
-              value: "just now"
-              attributes:
-                class:
-                  - "text-muted"
-          content: "See? Just like this."
-        - type: "pattern"
-          id: "toast"
-          attributes:
-            class:
-              - "show"
-          header:
-            - theme: "image"
-              uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIHJvdW5kZWQgbWUtMiIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzAwN2FmZiI+PC9yZWN0Pjwvc3ZnPg=="
-              attributes:
-                class:
-                  - "rounded"
-                  - "me-2"
-            - type: "html_tag"
-              tag: "strong"
-              value: "Bootstrap"
-              attributes:
-                class:
-                  - "me-auto"
-            - type: "html_tag"
-              tag: "small"
-              value: "2 seconds ago"
-              attributes:
-                class:
-                  - "text-muted"
-          content: "Heads up, toasts will stack automatically"
-        - type: "pattern"
-          id: "toast"
-          attributes:
-            class:
-              - "show"
-          content: "Hello, world! This is a toast message."
-          flex_wrapper: true
-        - type: "pattern"
-          id: "toast"
-          attributes:
-            class:
-              - "show"
-          content:
-            - markup: "Hello, world! This is a toast message."
-            - type: "html_tag"
-              tag: "div"
-              attributes:
-                class:
-                  - "mt-2"
-                  - "pt-2"
-                  - "border-top"
-            - type: "pattern"
-              id: "button"
-              variant: "primary__sm"
-              fields:
-                label: "Take action"
-            - type: "pattern"
-              id: "button"
-              variant: "secondary__sm"
-              fields:
-                label: "Close"
-              attributes:
-                data-bs-dismiss: "toast"
-          hide_close_button: true
-        - type: "pattern"
-          id: "toast"
-          attributes:
-            class:
-              - "show"
-              - "align-items-center"
-              - "text-bg-primary"
-              - "border-0"
-          content: "Hello, world! This is a toast message."
-          flex_wrapper: true
-          close_button_variant: "white"
diff --git a/templates/overrides/region/region--help.html.twig b/templates/region/region--help.html.twig
similarity index 82%
rename from templates/overrides/region/region--help.html.twig
rename to templates/region/region--help.html.twig
index ae795f73dc058ff7037d65c8df87e7ed996dd097..51bb7158f18924da3f15877d948d40157a2fc97d 100644
--- a/templates/overrides/region/region--help.html.twig
+++ b/templates/region/region--help.html.twig
@@ -16,10 +16,10 @@
 #}
 
 {% if content %}
-  {{ pattern('alert', {
-    'variant': 'info',
-    'attributes': attributes,
+  {{ include('ui_suite_bootstrap:alert', {
     'message': content,
-    'dismissible': false
-  }) }}
+    'attributes': attributes,
+    'variant': 'info',
+    'dismissible': false,
+  }, with_context = false) }}
 {% endif %}
diff --git a/templates/overrides/region/region--navigation-collapsible.html.twig b/templates/region/region--navigation-collapsible.html.twig
similarity index 100%
rename from templates/overrides/region/region--navigation-collapsible.html.twig
rename to templates/region/region--navigation-collapsible.html.twig
diff --git a/templates/overrides/region/region--no-wrapper.html.twig b/templates/region/region--no-wrapper.html.twig
similarity index 100%
rename from templates/overrides/region/region--no-wrapper.html.twig
rename to templates/region/region--no-wrapper.html.twig
diff --git a/templates/overrides/system/breadcrumb.html.twig b/templates/system/breadcrumb.html.twig
similarity index 66%
rename from templates/overrides/system/breadcrumb.html.twig
rename to templates/system/breadcrumb.html.twig
index 4bfe2a1b41345b65bf2b3f2d3dae6fccb4095183..240d80f70ec9adc2e7657b5712bb6ab47548a8ec 100644
--- a/templates/overrides/system/breadcrumb.html.twig
+++ b/templates/system/breadcrumb.html.twig
@@ -10,7 +10,7 @@
  */
 #}
 {% if breadcrumb %}
-  {{ pattern('breadcrumb', {
-    'items': breadcrumb
-  }) }}
+  {{ include('ui_suite_bootstrap:breadcrumb', {
+    'items': breadcrumb,
+  }, with_context = false) }}
 {% endif %}
diff --git a/templates/system/container--media-library-widget-selection.html.twig b/templates/system/container--media-library-widget-selection.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..8c55df7479830a82ff194b0b3287092816db23d4
--- /dev/null
+++ b/templates/system/container--media-library-widget-selection.html.twig
@@ -0,0 +1,33 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a container used to wrap child elements.
+ *
+ * Used for grouped form items. Can also be used as a theme wrapper for any
+ * renderable element, to surround it with a <div> and HTML attributes.
+ * See \Drupal\Core\Render\Element\RenderElementBase for more
+ * information on the #theme_wrappers render array property, and
+ * \Drupal\Core\Render\Element\Container for usage of the container render
+ * element.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - children: The rendered child elements of the container.
+ * - has_parent: A flag to indicate that the container has one or more parent
+     containers.
+ *
+ * @see template_preprocess_container()
+ *
+ * @ingroup themeable
+ */
+#}
+{%
+  set classes = [
+    has_parent ? 'js-form-wrapper',
+    has_parent ? 'form-wrapper',
+    'row',
+    'mb-3',
+    'media-library-widget-wrapper',
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>{{ children }}</div>
diff --git a/templates/overrides/system/details--accordion.html.twig b/templates/system/details--accordion.html.twig
similarity index 87%
rename from templates/overrides/system/details--accordion.html.twig
rename to templates/system/details--accordion.html.twig
index f09fb8c12d3501c2a564535525b87b99e553f557..a803fd11c265185d64676d4dc52e8ade3c93d6dc 100644
--- a/templates/overrides/system/details--accordion.html.twig
+++ b/templates/system/details--accordion.html.twig
@@ -19,6 +19,8 @@
 #}
 {% set accordion_id = 'accordion--' ~ random() %}
 {% set accordion_item_id = 'heading--' ~ accordion_id %}
+{% set accordion_attributes = create_attribute(accordion_attributes|default({})) %}
+{% set accordion_attributes = accordion_attributes.addClass('accordion').setAttribute('id', accordion_id) %}
 {%
   set summary_classes = [
     required ? 'js-form-required',
@@ -30,13 +32,13 @@
   set button_attributes = create_attribute({
     'class': [
       'accordion-button',
-      'collapsed'
+      'collapsed',
     ],
     'type': 'button',
     'data-bs-toggle': 'collapse',
     'data-bs-target': '#' ~ accordion_item_id,
     'aria-controls': accordion_item_id,
-    'aria-expanded': 'false'
+    'aria-expanded': 'false',
   })
 %}
 {%
@@ -44,12 +46,12 @@
     'id': accordion_item_id,
     'class': [
       'accordion-collapse',
-      'collapse'
+      'collapse',
     ],
-    'aria-labelledby': 'heading--' ~ accordion_item_id
+    'aria-labelledby': 'heading--' ~ accordion_item_id,
+    'data-bs-parent': '#' ~ accordion_id,
   })
 %}
-{% set content_attributes = accordion_id ? content_attributes.setAttribute('data-bs-parent', '#' ~ accordion_id) : content_attributes %}
 {% if attributes.hasAttribute('open') %}
   {% set button_attributes = button_attributes.setAttribute('aria-expanded', 'true') %}
   {% set button_attributes = button_attributes.removeClass('collapsed') %}
@@ -64,7 +66,7 @@
 %}
 {% set description_attributes = create_attribute(description_attributes|default({})) %}
 
-<div class="accordion mb-3" id="{{ accordion_id }}">
+<div{{ accordion_attributes }}>
   <div{{ attributes.addClass('accordion-item') }}>
     {%- if title -%}
       <h2{{ summary_attributes.addClass(summary_classes).setAttribute('id', 'heading--' ~ accordion_item_id) }}>
diff --git a/templates/overrides/system/field.html.twig b/templates/system/field.html.twig
similarity index 100%
rename from templates/overrides/system/field.html.twig
rename to templates/system/field.html.twig
diff --git a/templates/overrides/system/fieldset.html.twig b/templates/system/fieldset.html.twig
similarity index 100%
rename from templates/overrides/system/fieldset.html.twig
rename to templates/system/fieldset.html.twig
diff --git a/templates/overrides/system/html.html.twig b/templates/system/html.html.twig
similarity index 100%
rename from templates/overrides/system/html.html.twig
rename to templates/system/html.html.twig
diff --git a/templates/overrides/system/image.html.twig b/templates/system/image.html.twig
similarity index 100%
rename from templates/overrides/system/image.html.twig
rename to templates/system/image.html.twig
diff --git a/templates/system/item-list--layouts.html.twig b/templates/system/item-list--layouts.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..779ef923399a58a150a17c125fb42c6d14d55575
--- /dev/null
+++ b/templates/system/item-list--layouts.html.twig
@@ -0,0 +1,60 @@
+{#
+/**
+ * @file
+ * Default theme implementation for an item list.
+ *
+ * Available variables:
+ * - items: A list of items. Each item contains:
+ *   - attributes: HTML attributes to be applied to each list item.
+ *   - value: The content of the list element.
+ * - title: The title of the list.
+ * - list_type: The tag for list element ("ul" or "ol").
+ * - wrapper_attributes: HTML attributes to be applied to the list wrapper.
+ * - attributes: HTML attributes to be applied to the list.
+ * - empty: A message to display when there are no items. Allowed value is a
+ *   string or render array.
+ * - context: A list of contextual data associated with the list. May contain:
+ *   - list_style: The custom list style.
+ *
+ * @see template_preprocess_item_list()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if context.list_style %}
+  {%- set attributes = attributes.addClass('item-list__' ~ context.list_style) %}
+{% endif %}
+{% if items or empty %}
+  {%- if title is not empty -%}
+    <h3>{{ title }}</h3>
+  {%- endif -%}
+
+  {%- if items -%}
+    {# Prepare list group items. #}
+    {% set layouts = [] %}
+    {% for item in items %}
+      {% set layouts = layouts|merge([{
+        '#type': 'component',
+        '#component': 'ui_suite_bootstrap:list_group_item',
+        '#slots': {
+          'content': item.value|add_class([
+            'd-flex',
+            'flex-wrap',
+            'align-items-center',
+            'gap-2',
+          ]),
+        },
+        '#props': {
+          'attributes': item.attributes,
+        },
+      }]) %}
+    {% endfor %}
+
+    {{ include('ui_suite_bootstrap:list_group', {
+      'items': layouts,
+      'variant': 'flush',
+    }, with_context = false) }}
+  {%- else -%}
+    {{- empty -}}
+  {%- endif -%}
+{%- endif %}
diff --git a/templates/overrides/system/links--comment.html.twig b/templates/system/links--comment.html.twig
similarity index 100%
rename from templates/overrides/system/links--comment.html.twig
rename to templates/system/links--comment.html.twig
diff --git a/templates/overrides/system/links--dropbutton.html.twig b/templates/system/links--dropbutton.html.twig
similarity index 100%
rename from templates/overrides/system/links--dropbutton.html.twig
rename to templates/system/links--dropbutton.html.twig
diff --git a/templates/system/links--media-library-menu.html.twig b/templates/system/links--media-library-menu.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..709df74ac1ef8ed8f06a38f553f309a2103d8262
--- /dev/null
+++ b/templates/system/links--media-library-menu.html.twig
@@ -0,0 +1,83 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a set of links.
+ *
+ * Available variables:
+ * - attributes: Attributes for the UL containing the list of links.
+ * - links: Links to be output.
+ *   Each link will have the following elements:
+ *   - link: (optional) A render array that returns a link. See
+ *     template_preprocess_links() for details how it is generated.
+ *   - text: The link text.
+ *   - attributes: HTML attributes for the list item element.
+ *   - text_attributes: (optional) HTML attributes for the span element if no
+ *     'url' was supplied.
+ * - heading: (optional) A heading to precede the links.
+ *   - text: The heading text.
+ *   - level: The heading level (e.g. 'h2', 'h3').
+ *   - attributes: (optional) A keyed list of attributes for the heading.
+ *   If the heading is a string, it will be used as the text of the heading and
+ *   the level will default to 'h2'.
+ *
+ *   Headings should be used on navigation menus and any list of links that
+ *   consistently appears on multiple pages. To make the heading invisible use
+ *   the 'visually-hidden' CSS class. Do not use 'display:none', which
+ *   removes it from screen readers and assistive technology. Headings allow
+ *   screen reader and keyboard only users to navigate to or skip the links.
+ *   See http://juicystudio.com/article/screen-readers-display-none.php and
+ *   http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
+ *
+ * @see template_preprocess_links()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if links -%}
+  {%- if heading -%}
+    {%- if heading.level -%}
+      <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}</{{ heading.level }}>
+    {%- else -%}
+      <h2{{ heading.attributes }}>{{ heading.text }}</h2>
+    {%- endif -%}
+  {%- endif -%}
+
+  {% if preprocessed_items -%}
+    {% set prepared_items = [] %}
+    {% for item in preprocessed_items %}
+      {% set link_attributes = create_attribute(item.link_attributes|default({})) %}
+      {% set prepared_items = prepared_items|merge([{
+        '#type': 'component',
+        '#component': 'ui_suite_bootstrap:list_group_item',
+        '#slots': {
+          'content': item.title,
+        },
+        '#props': {
+          'attributes': link_attributes,
+          'url': item.url,
+          'active': link_attributes.hasClass('active'),
+        },
+      }]) %}
+    {% endfor %}
+
+    {{ include('ui_suite_bootstrap:list_group', {
+      items: prepared_items,
+      attributes: attributes,
+      variant: 'flush',
+    }, with_context = false) }}
+  {%- else -%}
+    <ul{{ attributes }}>
+      {%- for item in links -%}
+        <li{{ item.attributes }}>
+          {%- if item.link -%}
+            {{ item.link }}
+          {%- elseif item.text_attributes -%}
+            <span{{ item.text_attributes }}>{{ item.text }}</span>
+          {%- else -%}
+            {{ item.text }}
+          {%- endif -%}
+        </li>
+      {%- endfor -%}
+    </ul>
+  {%- endif -%}
+{%- endif %}
diff --git a/templates/overrides/system/links.html.twig b/templates/system/links.html.twig
similarity index 100%
rename from templates/overrides/system/links.html.twig
rename to templates/system/links.html.twig
diff --git a/templates/overrides/system/maintenance-page.html.twig b/templates/system/maintenance-page.html.twig
similarity index 100%
rename from templates/overrides/system/maintenance-page.html.twig
rename to templates/system/maintenance-page.html.twig
diff --git a/templates/overrides/system/mark.html.twig b/templates/system/mark.html.twig
similarity index 64%
rename from templates/overrides/system/mark.html.twig
rename to templates/system/mark.html.twig
index 7dbdc89fa8c2fabca620d1e18071d41168165276..4b0a9b8a033a0a6cd65bcf5f0e1cc273ce647071 100644
--- a/templates/overrides/system/mark.html.twig
+++ b/templates/system/mark.html.twig
@@ -15,22 +15,22 @@
 #}
 {% if logged_in %}
   {% if status is constant('MARK_NEW') %}
-    {{ pattern('badge', {
+    {{ include('ui_suite_bootstrap:badge', {
       'label': 'New'|t,
-      'attributes': create_attribute({
+      'attributes': {
         'class': [
-          'text-bg-light'
-        ]
-      }),
-    }) }}
+          'text-bg-light',
+        ],
+      },
+    }, with_context = false) }}
   {% elseif status is constant('MARK_UPDATED') %}
-    {{ pattern('badge', {
+    {{ include('ui_suite_bootstrap:badge', {
       'label': 'Updated'|t,
-      'attributes': create_attribute({
+      'attributes': {
         'class': [
-          'text-bg-info'
-        ]
-      }),
-    }) }}
+          'text-bg-info',
+        ],
+      },
+    }, with_context = false) }}
   {% endif %}
 {% endif %}
diff --git a/templates/overrides/system/page.html.twig b/templates/system/page.html.twig
similarity index 98%
rename from templates/overrides/system/page.html.twig
rename to templates/system/page.html.twig
index b680f090662227595112f8fd6c44c577a7899e9a..88bbbaad41508506e012cdf6cfdc992b77815b96 100644
--- a/templates/overrides/system/page.html.twig
+++ b/templates/system/page.html.twig
@@ -49,14 +49,14 @@
 {% if page.navigation or page.navigation_collapsible %}
   {% block navbar %}
     <div class="{{ container }} bg-light">
-      {{ pattern('navbar', {
+      {{ include('ui_suite_bootstrap:navbar', {
+        navigation: page.navigation,
+        navigation_collapsible: page.navigation_collapsible,
         variant: 'expand_lg',
         placement: 'default',
-        toggler_position: 'end',
         toggle_action: 'collapse',
-        navigation: page.navigation,
-        navigation_collapsible: page.navigation_collapsible,
-      }) }}
+        toggler_position: 'end',
+      }, with_context = false) }}
     </div>
   {% endblock %}
 {% endif %}
diff --git a/templates/system/pager--media-library.html.twig b/templates/system/pager--media-library.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..567852acf9eef8797df299c99f5575bd99b288bc
--- /dev/null
+++ b/templates/system/pager--media-library.html.twig
@@ -0,0 +1,45 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a pager.
+ *
+ * Available variables:
+ * - heading_id: Pagination heading ID.
+ * - pagination_heading_level: The heading level to use for the pager.
+ * - items: List of pager items.
+ *   The list is keyed by the following elements:
+ *   - first: Item for the first page; not present on the first page of results.
+ *   - previous: Item for the previous page; not present on the first page
+ *     of results.
+ *   - next: Item for the next page; not present on the last page of results.
+ *   - last: Item for the last page; not present on the last page of results.
+ *   - pages: List of pages, keyed by page number.
+ *   Sub-sub elements:
+ *   items.first, items.previous, items.next, items.last, and each item inside
+ *   items.pages contain the following elements:
+ *   - href: URL with appropriate query parameters for the item.
+ *   - attributes: A keyed list of HTML attributes for the item.
+ *   - text: The visible text used for the item link, such as "‹ Previous"
+ *     or "Next ›".
+ * - current: The page number of the current page.
+ * - ellipses: If there are more pages than the quantity allows, then an
+ *   ellipsis before or after the listed pages may be present.
+ *   - previous: Present if the currently visible list of pages does not start
+ *     at the first page.
+ *   - next: Present if the visible list of pages ends before the last page.
+ *
+ * @see template_preprocess_pager()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if items %}
+  {{ include('ui_suite_bootstrap:pagination', {
+    'attributes': attributes.addClass([
+      'js-pager__items',
+      'mt-3',
+      'mb-0',
+    ]),
+    'items': preprocessed_items,
+  }, with_context = false) }}
+{% endif %}
diff --git a/templates/overrides/system/pager.html.twig b/templates/system/pager.html.twig
similarity index 95%
rename from templates/overrides/system/pager.html.twig
rename to templates/system/pager.html.twig
index 603f229b1c76dda9e3ed61783e22b816e2955e2b..120b2d336fd5dfd2e4a7891706355ed82be2792d 100644
--- a/templates/overrides/system/pager.html.twig
+++ b/templates/system/pager.html.twig
@@ -34,8 +34,8 @@
  */
 #}
 {% if items %}
-  {{ pattern('pagination', {
-    'items': preprocessed_items,
+  {{ include('ui_suite_bootstrap:pagination', {
     'attributes': attributes.addClass('js-pager__items'),
-  }) }}
+    'items': preprocessed_items,
+  }, with_context = false) }}
 {% endif %}
diff --git a/templates/overrides/system/progress-bar.html.twig b/templates/system/progress-bar.html.twig
similarity index 87%
rename from templates/overrides/system/progress-bar.html.twig
rename to templates/system/progress-bar.html.twig
index 4c148add70dd20101cfeb9713772d0f51864eb50..fa21541fdf763836b9d535f72041f4f9287546ff 100644
--- a/templates/overrides/system/progress-bar.html.twig
+++ b/templates/system/progress-bar.html.twig
@@ -16,13 +16,13 @@
     <div class="progress__label">{{ label }}</div>
   {% endif %}
 
-  {{ pattern('progress', {
-    variant: 'striped__animated',
-    attributes: attributes,
+  {{ include('ui_suite_bootstrap:progress', {
     label: percent,
+    attributes: attributes,
+    variant: 'striped__animated',
     aria_label: label,
-    percent: percent
-  }) }}
+    percent: percent,
+  }, with_context = false) }}
 
   {% if message %}
     <div class="progress__description">{{ message }}</div>
diff --git a/templates/overrides/system/status-messages.html.twig b/templates/system/status-messages.html.twig
similarity index 77%
rename from templates/overrides/system/status-messages.html.twig
rename to templates/system/status-messages.html.twig
index 6776ab21f409eb71a63fdbdb464030eb5c5784b4..f8924b11b969d595474352c9f4bbe2759435d645 100644
--- a/templates/overrides/system/status-messages.html.twig
+++ b/templates/system/status-messages.html.twig
@@ -28,16 +28,11 @@
   {% set variant = (type == 'error') ? 'danger' : variant %}
 
   {% for message in messages %}
-    {#
-    Ensure each pattern have its own attributes to not interfere on other
-    messages by changing the main attributes object.
-    #}
-    {% set pattern_attributes = create_attribute(attributes.toArray()) %}
-    {{ pattern('alert', {
-      'variant': variant,
-      'attributes': pattern_attributes,
+    {{ include('ui_suite_bootstrap:alert', {
       'message': message,
-      'dismissible': true
-    }) }}
+      'attributes': attributes,
+      'variant': variant,
+      'dismissible': true,
+    }, with_context = false) }}
   {% endfor %}
 {% endfor %}
diff --git a/templates/overrides/system/table.html.twig b/templates/system/table.html.twig
similarity index 77%
rename from templates/overrides/system/table.html.twig
rename to templates/system/table.html.twig
index 9cfe0d67f769081786552c1732f5acbaee4d3b5e..4c2235855798a2a4e425fc80bc7c3e0105cc9734 100644
--- a/templates/overrides/system/table.html.twig
+++ b/templates/system/table.html.twig
@@ -53,22 +53,25 @@
 {% set caption_top = caption_top ? caption_top : 'false' %}
 {% set header_color = header_color ? header_color : '' %}
 {% set footer_color = footer_color ? footer_color : '' %}
-{# @todo Remove sticky-enabled when Core 10.3 will become minimum supported version. #}
-{% set attributes = sticky ? attributes.addClass('sticky-enabled sticky-header') : attributes %}
+{% set attributes = sticky ? attributes.addClass('sticky-header') : attributes %}
 
 {# Prepare header in the expected format. #}
 {% set prepared_header = [] %}
 {% for cell in header %}
   {% set active = cell.active_table_sort ?: false %}
   {% set active = active ?: cell.attributes.hasClass('is-active') %}
-  {% set prepared_header = prepared_header|merge([
-    pattern('table_cell', {
+  {% set prepared_header = prepared_header|merge([{
+    '#type': 'component',
+    '#component': 'ui_suite_bootstrap:table_cell',
+    '#slots': {
+      'content': cell.content,
+    },
+    '#props': {
       'attributes': cell.attributes,
+      'active': active,
       'tag': cell.tag,
-      'content': cell.content,
-      'active': active
-    })
-  ]) %}
+    },
+  }]) %}
 {% endfor %}
 
 {# Prepare rows in the expected format. #}
@@ -78,22 +81,30 @@
   {% for cell in row.cells %}
     {% set active = cell.active_table_sort ?: false %}
     {% set active = active ?: cell.attributes.hasClass('is-active') %}
-    {% set prepared_cells = prepared_cells|merge([
-      pattern('table_cell', {
+    {% set prepared_cells = prepared_cells|merge([{
+      '#type': 'component',
+      '#component': 'ui_suite_bootstrap:table_cell',
+      '#slots': {
+        'content': cell.content,
+      },
+      '#props': {
         'attributes': cell.attributes,
+        'active': active,
         'tag': cell.tag,
-        'content': cell.content,
-        'active': active
-      })
-    ]) %}
+      },
+    }]) %}
   {% endfor %}
 
-  {% set prepared_rows = prepared_rows|merge([
-    pattern('table_row', {
+  {% set prepared_rows = prepared_rows|merge([{
+    '#type': 'component',
+    '#component': 'ui_suite_bootstrap:table_row',
+    '#slots': {
+      'cells': prepared_cells,
+    },
+    '#props': {
       'attributes': row.attributes,
-      'cells': prepared_cells
-    })
-  ]) %}
+    },
+  }]) %}
 {% endfor %}
 
 {# Prepare footer in the expected format. #}
@@ -103,27 +114,41 @@
   {% for cell in row.cells %}
     {% set active = cell.active_table_sort ?: false %}
     {% set active = active ?: cell.attributes.hasClass('is-active') %}
-    {% set prepared_cells = prepared_cells|merge([
-      pattern('table_cell', {
+    {% set prepared_cells = prepared_cells|merge([{
+      '#type': 'component',
+      '#component': 'ui_suite_bootstrap:table_cell',
+      '#slots': {
+        'content': cell.content,
+      },
+      '#props': {
         'attributes': cell.attributes,
+        'active': active,
         'tag': cell.tag,
-        'content': cell.content,
-        'active': active
-      })
-    ]) %}
+      },
+    }]) %}
   {% endfor %}
 
-  {% set prepared_footer = prepared_footer|merge([
-    pattern('table_row', {
+  {% set prepared_footer = prepared_footer|merge([{
+    '#type': 'component',
+    '#component': 'ui_suite_bootstrap:table_row',
+    '#slots': {
+      'cells': prepared_cells,
+    },
+    '#props': {
       'attributes': row.attributes,
-      'cells': prepared_cells
-    })
-  ]) %}
+    },
+  }]) %}
 {% endfor %}
 
-{{ pattern('table', {
-  variant: 'default',
+{{ include('ui_suite_bootstrap:table', {
+  caption: caption,
+  header: prepared_header,
+  colgroups: colgroups,
+  rows: prepared_rows,
+  footer: prepared_footer,
+  empty: empty,
   attributes: attributes,
+  variant: 'default',
   header_color: header_color,
   footer_color: footer_color,
   stripes: stripes,
@@ -131,12 +156,6 @@
   hover: hover,
   responsive: responsive,
   divider: divider,
-  caption: caption,
   caption_top: caption_top,
-  header: prepared_header,
   header_columns: header_columns,
-  colgroups: colgroups,
-  rows: prepared_rows,
-  footer: prepared_footer,
-  empty: empty
-}) }}
+}, with_context = false) }}
diff --git a/templates/overrides/taxonomy/taxonomy-term--bare.html.twig b/templates/taxonomy/taxonomy-term--bare.html.twig
similarity index 100%
rename from templates/overrides/taxonomy/taxonomy-term--bare.html.twig
rename to templates/taxonomy/taxonomy-term--bare.html.twig
diff --git a/templates/overrides/taxonomy/taxonomy-term.html.twig b/templates/taxonomy/taxonomy-term.html.twig
similarity index 100%
rename from templates/overrides/taxonomy/taxonomy-term.html.twig
rename to templates/taxonomy/taxonomy-term.html.twig
diff --git a/templates/overrides/ui_examples/ui-examples-overview-page.html.twig b/templates/ui_examples/ui-examples-overview-page.html.twig
similarity index 100%
rename from templates/overrides/ui_examples/ui-examples-overview-page.html.twig
rename to templates/ui_examples/ui-examples-overview-page.html.twig
diff --git a/templates/ui_patterns_library/ui-patterns-component-metadata.html.twig b/templates/ui_patterns_library/ui-patterns-component-metadata.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..87c4667f9ab740b0df8a5b8a7082e7010a51ff55
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-component-metadata.html.twig
@@ -0,0 +1,54 @@
+{#
+/**
+ * @file
+ * UI Patterns meta information.
+ */
+#}
+{% if component is not empty %}
+  <p class="ui_patterns_component__id">
+    ID: <code>{{ component.id }}</code>
+  </p>
+  {% if component.description %}<p class="ui_patterns_component__description">{{ component.description }}</p>{% endif %}
+  {% if component.status %}
+    <p class="ui_patterns_component__status ui_patterns_component__status--{{ component.status }}">
+      {{ 'Status: @status'|t({'@status': component.status}) }}
+    </p>
+  {% endif %}
+  {% if component.links %}
+    <div class="ui_patterns_component__links">
+      {% if component.links|length > 1 %}
+        {{ 'Links:'|t }}
+        <ul>
+          {% for link in component.links %}
+            <li class="ui_patterns_component__link">
+              <a href="{{ link.url }}" class="btn btn-sm btn-primary">{{ link.title|default('External documentation'|t) }}</a>
+            </li>
+          {% endfor %}
+        </ul>
+      {% else %}
+        <p class="ui_patterns_component__link">
+          {% set link = component.links|first %}
+          <a href="{{ link.url }}" class="btn btn-sm btn-primary">{{ link.title|default('External documentation'|t) }}</a>
+        </p>
+      {% endif %}
+    </div>
+  {% endif %}
+  {% if component.replaces %}
+    <p>
+      {{ 'Replaces'|t }}: <a href="{{ url('ui_patterns_library.single', {provider: component.replaces|split(':')|first, machineName: component.replaces|split(':')|last}) }}">{{ component.replaces }}</a>
+    </p>
+  {% endif %}
+
+  {% if component.tags %}
+    <p class="ui_patterns_component__tags">
+      {% for tag in component.tags %}
+        {{ include('ui_suite_bootstrap:badge', {
+          label: tag,
+          attributes: {
+            class: ['text-bg-secondary']
+          },
+        }, with_context = false) }}
+      {% endfor %}
+    </p>
+  {% endif %}
+{% endif %}
diff --git a/templates/ui_patterns_library/ui-patterns-component-table.html.twig b/templates/ui_patterns_library/ui-patterns-component-table.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f39ba4596995c16492814d4add5fdb4a58cf20f7
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-component-table.html.twig
@@ -0,0 +1,49 @@
+{#
+/**
+ * @file
+ * UI Pattern meta information.
+ */
+#}
+{% if component.slots or component.props %}
+<div class="table-responsive">
+  <table class="ui_patterns_component_table table" style="width: 100%;">
+    <thead>
+      <tr>
+        <th>{{ 'Name'|t }}</th>
+        <th>{{ 'Label'|t }}</th>
+        <th>{{ 'Type'|t }}</th>
+        <th>{{ 'Description'|t }}</th>
+      </tr>
+    </thead>
+    <tbody>
+      {% for slot_id, slot in component.slots %}
+        <tr class="ui_patterns_component_table__slot">
+          <td>
+            <code>{{ slot_id }}</code>
+          </td>
+          <td>{{ slot.title }}</td>
+          <td>{{ 'Slot'|t }}</td>
+          <td>{{ slot.description }}</td>
+        </tr>
+      {% endfor %}
+      {% for prop_id, prop in component.props.properties %}
+        {% if prop_id != 'attributes' and prop_id != 'variant' %}
+          <tr class="ui_patterns_component_table__prop">
+            <td>
+              <code>{{ prop_id }}</code>
+            </td>
+            <td>{{ prop.title }}</td>
+            <td>{{ prop.ui_patterns.type_definition.label }}</td>
+            <td>
+              {%- for line in prop.ui_patterns.summary -%}
+                {{- line -}}
+                <br>
+              {%- endfor -%}
+            </td>
+          </tr>
+        {% endif %}
+      {% endfor %}
+    </tbody>
+  </table>
+</div>
+{% endif %}
diff --git a/templates/ui_patterns_library/ui-patterns-overview-page.html.twig b/templates/ui_patterns_library/ui-patterns-overview-page.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c9c2f2a9618edd5098e4f4f9bb65d2298d384081
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-overview-page.html.twig
@@ -0,0 +1,44 @@
+{#
+/**
+ * @file
+ * UI Pattern library page template, override this in your theme.
+ */
+#}
+
+{% if groups is not empty %}
+
+{% set content = include('ui-patterns-overview-quicklinks.html.twig', {groups: groups}, with_context=false) %}
+<button class="btn btn-primary position-fixed bottom-0 end-0 mb-2 me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#menu-patterns" aria-controls="menu-patterns">
+  {{ 'Navigation'|t }}
+</button>
+{{ include('ui_suite_bootstrap:offcanvas', {
+  title: 'Available components'|t,
+  body: content,
+  variant: 'start',
+  offcanvas_id: 'menu-patterns',
+  backdrop: 'false',
+  scroll: true,
+  heading_level: 2,
+}, with_context = false) }}
+
+<div class="row">
+  <div data-bs-spy="scroll" data-bs-target="#components-library" data-bs-smooth-scroll="true" tabindex="0" class="col col-12">
+  {% for components in groups %}
+    {% for component in components %}
+      <div class="ui_patterns_component" id="{{ component.id|clean_id }}">
+        <h2 class="ui_patterns_component__title my-3">
+          <a href="{{ url('ui_patterns_library.single', {provider: component.provider, machineName: component.machineName}) }}"
+             class="component__link display-3">{{ component.name }}</a>
+        </h2>
+        {{ include('ui-patterns-component-metadata.html.twig', {component: component}, with_context=false) }}
+        {{ include('ui-patterns-component-table.html.twig', {component: component}, with_context=false) }}
+        {% if component.stories %}
+          {{ include('ui-patterns-stories-compact.html.twig', {component: component}, with_context=false) }}
+        {% endif %}
+      </div>
+      <hr class="my-5">
+    {% endfor %}
+  {% endfor %}
+   </div>
+</div>
+{% endif %}
diff --git a/templates/ui_patterns_library/ui-patterns-overview-quicklinks.html.twig b/templates/ui_patterns_library/ui-patterns-overview-quicklinks.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..edfd43729959135beb573b4b7407906a9d11513c
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-overview-quicklinks.html.twig
@@ -0,0 +1,30 @@
+{#
+/**
+ * @file
+ * UI Patterns components menu.
+ */
+#}
+{% if groups %}
+  <div id="components-library" class="ui_patterns_quicklinks" class="overflow-auto">
+    {% if groups|length > 1 %}
+      {% for group_name, components in groups %}
+        <h3 class="ui_patterns_quicklinks__group">{{ group_name }}</h3>
+        <ul class="nav nav-pills flex-column">
+          {% for component in components %}
+            <li class="nav-item">
+              <a class="nav-link p-1" href="#{{ component.id|clean_id }}">{{ component.name }}</a>
+            </li>
+          {% endfor %}
+        </ul>
+      {% endfor %}
+    {% else %}
+        <ul class="nav nav-pills flex-column">
+        {% for component in components %}
+          <li class="nav-item">
+            <a class="nav-link p-1" href="#{{ component.id }}">{{ component.name }}</a>
+          </li>
+        {% endfor %}
+      </ul>
+    {% endif %}
+  </div>
+{% endif %}
diff --git a/templates/ui_patterns_library/ui-patterns-stories-compact.html.twig b/templates/ui_patterns_library/ui-patterns-stories-compact.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..9f7b876c1f29892da247e73460dc93545614f672
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-stories-compact.html.twig
@@ -0,0 +1,20 @@
+<div class="ui_patterns_component__stories">
+  {% for story_id, story in component.stories %}
+    {{ _self.render_story(component.id, story_id, story, component.variants) }}
+  {% endfor %}
+</div>
+{% macro render_story(component_id, story_id, story, variants) %}
+  <div class="ui_patterns_story">
+    {% if variants and not story.props.variant %}
+      {% for variant_id, variant in variants %}
+        <div class="mb-2">
+        {{ component_story(component_id, story_id, {}, {variant: variant_id}) }}
+        </div>
+      {% endfor %}
+    {% else %}
+      <div class="mb-2">
+      {{ component_story(component_id, story_id) }}
+      </div>
+    {% endif %}
+  </div>
+{% endmacro %}
diff --git a/templates/ui_patterns_library/ui-patterns-stories-full.html.twig b/templates/ui_patterns_library/ui-patterns-stories-full.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..3f3db7cc9c8059f99607dba84d680d70198e4520
--- /dev/null
+++ b/templates/ui_patterns_library/ui-patterns-stories-full.html.twig
@@ -0,0 +1,29 @@
+<div class="ui_patterns_component__stories">
+  {% for story_id, story in component.stories %}
+    {{ _self.render_story(component.id, story_id, story, component.variants) }}
+  {% endfor %}
+</div>
+{% macro render_story(component_id, story_id, story, variants) %}
+  <div class="ui_patterns_story">
+    <h2 class="ui_patterns_story__name my-3">{{ story.name }}</h2>
+    {% if story.description %}<p class="ui_patterns_story__description">{{ story.description }}</p>{% endif %}
+    <div class="ui_patterns_story__story">
+      {% if variants and not story.props.variant %}
+        {% for variant_id, variant in variants %}
+          {{ _self.render_variant(component_id, story_id, variant_id, variant) }}
+        {% endfor %}
+      {% else %}
+        {{ component_story(component_id, story_id, {}, {}, true) }}
+      {% endif %}
+    </div>
+  </div>
+{% endmacro %}
+{% macro render_variant(component_id, story_id, variant_id, variant) %}
+  <div class="ui_patterns_variant">
+    <h3 class="ui_patterns_variant__title my-3">
+      {{ variant.title }} (<code>{{ variant_id }}</code>)
+    </h3>
+    {% if variant.description %}<p class="ui_patterns_variant__description">{{ variant.description }}</p>{% endif %}
+    {{ component_story(component_id, story_id, {}, {variant: variant_id}, true) }}
+  </div>
+{% endmacro %}
diff --git a/templates/overrides/ui_styles_library/ui-styles-overview-page.html.twig b/templates/ui_styles_library/ui-styles-overview-page.html.twig
similarity index 76%
rename from templates/overrides/ui_styles_library/ui-styles-overview-page.html.twig
rename to templates/ui_styles_library/ui-styles-overview-page.html.twig
index 461220e397cac1d0a72cb940b85b4a627b5e22cf..3de4e20a7cfbf3bfd6ccf9601085eabeabe60c18 100644
--- a/templates/overrides/ui_styles_library/ui-styles-overview-page.html.twig
+++ b/templates/ui_styles_library/ui-styles-overview-page.html.twig
@@ -6,36 +6,24 @@
 #}
 
 {% if styles is not empty %}
-  {% set content %}
-    <div id="styles-library" class="overflow-auto">
-      {# List of available styles with anchor links. #}
-      {% for group_name, group_styles in styles %}
-        {% if styles|length > 1 %}
-          <h3>{{ group_name }}</h3>
-        {% endif %}
-        <ul class="nav nav-pills flex-column">
-          {% for style in group_styles %}
-            <li class="nav-item">
-              <a href="#{{ style.id }}" class="nav-link p-1">{{ style.label }}</a>
-            </li>
-          {% endfor %}
-        </ul>
-      {% endfor %}
-    </div>
-  {% endset %}
+  {% set content = include(
+    '@ui_suite_bootstrap/ui_styles_library/ui-styles-overview-quicklinks.html.twig',
+    {styles: styles},
+    with_context=false
+  ) %}
 
   <button class="btn btn-primary position-fixed bottom-0 end-0 mb-2 me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#menu-styles" aria-controls="menu-styles">
     {{ 'Navigation'|t }}
   </button>
-  {{ pattern('offcanvas', {
+  {{ include('ui_suite_bootstrap:offcanvas', {
+    title: 'Available styles'|t,
+    body: content,
     variant: 'start',
-    offcanvas_id: 'menu-styles',
     backdrop: 'false',
-    scroll: true,
     heading_level: 2,
-    title: 'Available styles'|t,
-    body: content
-  }) }}
+    offcanvas_id: 'menu-styles',
+    scroll: true,
+  }, with_context = false) }}
 
   <div class="row">
     <div data-bs-spy="scroll" data-bs-target="#styles-library" data-bs-smooth-scroll="true" tabindex="0" class="col col-12">
diff --git a/templates/ui_styles_library/ui-styles-overview-quicklinks.html.twig b/templates/ui_styles_library/ui-styles-overview-quicklinks.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f91e0cee85c0aa5239ce2493c4c4427ba609cc3a
--- /dev/null
+++ b/templates/ui_styles_library/ui-styles-overview-quicklinks.html.twig
@@ -0,0 +1,23 @@
+{#
+/**
+ * @file
+ * UI Styles styles menu.
+ */
+#}
+{% if styles %}
+  <div id="styles-library" class="overflow-auto">
+    {# List of available styles with anchor links. #}
+    {% for group_name, group_styles in styles %}
+      {% if styles|length > 1 %}
+        <h3>{{ group_name }}</h3>
+      {% endif %}
+      <ul class="nav nav-pills flex-column">
+        {% for style in group_styles %}
+          <li class="nav-item">
+            <a class="nav-link p-1" href="#{{ style.id }}">{{ style.label }}</a>
+          </li>
+        {% endfor %}
+      </ul>
+    {% endfor %}
+  </div>
+{% endif %}
diff --git a/templates/views/media_library/views-mini-pager--media-library.html.twig b/templates/views/media_library/views-mini-pager--media-library.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..74123071423c5030f014cf6aeeaa6708a5149fab
--- /dev/null
+++ b/templates/views/media_library/views-mini-pager--media-library.html.twig
@@ -0,0 +1,25 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a views mini-pager.
+ *
+ * Available variables:
+ * - heading_id: Pagination heading ID.
+ * - pagination_heading_level: The heading level to use for the pager.
+ * - items: List of pager items.
+ *
+ * @see template_preprocess_views_mini_pager()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if items.previous or items.next %}
+  {{ include('ui_suite_bootstrap:pagination', {
+    'attributes': attributes.addClass([
+      'js-pager__items',
+      'mt-3',
+      'mb-0',
+    ]),
+    'items': preprocessed_items,
+  }, with_context = false) }}
+{% endif %}
diff --git a/templates/views/media_library/views-view--media-library.html.twig b/templates/views/media_library/views-view--media-library.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c05c680c9a71bd9f95d7e8907d1531aa46f959b6
--- /dev/null
+++ b/templates/views/media_library/views-view--media-library.html.twig
@@ -0,0 +1,74 @@
+{#
+/**
+ * @file
+ * Theme override for the media_library view template.
+ *
+ * Exposed filters precede views header.
+ *
+ * Available variables:
+ * - attributes: Remaining HTML attributes for the element.
+ * - css_name: A CSS-safe version of the view name.
+ * - css_class: The user-specified classes names, if any.
+ * - header: The optional header.
+ * - footer: The optional footer.
+ * - rows: The results of the view query, if any.
+ * - empty: The content to display if there are no rows.
+ * - pager: The optional pager next/prev links to display.
+ * - exposed: Exposed widget form/info to display.
+ * - feed_icons: Optional feed icons to display.
+ * - more: An optional link to the next page of results.
+ * - title: Title of the view, only used when displaying in the admin preview.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the view title.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the view title.
+ * - attachment_before: An optional attachment view to be displayed before the
+ *   view content.
+ * - attachment_after: An optional attachment view to be displayed after the
+ *   view content.
+ * - dom_id: Unique id for every view being printed to give unique class for
+ *   JavaScript.
+ *
+ * @see template_preprocess_views_view()
+ *
+ * @ingroup themeable
+ */
+#}
+{%
+  set classes = [
+    dom_id ? 'js-view-dom-id-' ~ dom_id,
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {{ title_prefix }}
+  {{ title }}
+  {{ title_suffix }}
+
+  {{ exposed }}
+
+  {% if header %}
+    <header class="m-1">
+      {{ header }}
+    </header>
+  {% endif %}
+
+  {{ attachment_before }}
+
+  {% if rows -%}
+    {{ rows }}
+  {% elseif empty -%}
+    {{ empty }}
+  {% endif %}
+  {{ pager }}
+
+  {{ attachment_after }}
+  {{ more }}
+
+  {% if footer %}
+    <footer>
+      {{ footer }}
+    </footer>
+  {% endif %}
+
+  {{ feed_icons }}
+</div>
diff --git a/templates/views/media_library/views-view-unformatted--media-library.html.twig b/templates/views/media_library/views-view-unformatted--media-library.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..0856d04a8017f3061c3e3cf7e09c4b2b46be6e88
--- /dev/null
+++ b/templates/views/media_library/views-view-unformatted--media-library.html.twig
@@ -0,0 +1,39 @@
+{#
+/**
+ * @file
+ * Theme override for the media_library display of unformatted rows.
+ *
+ * Available variables:
+ * - title: The title of this group of rows. May be empty.
+ * - rows: A list of the view's row items.
+ *   - attributes: The row's HTML attributes.
+ *   - content: The row's content.
+ * - view: The view object.
+ * - default_row_class: A flag indicating whether default classes should be
+ *   used on rows.
+ *
+ * @see template_preprocess_views_view_unformatted()
+ */
+#}
+{% if title %}
+  <h3>{{ title }}</h3>
+{% endif %}
+
+<div{{ attributes.addClass('row') }}>
+  {% for row in rows %}
+    {%
+      set row_classes = [
+        default_row_class ? 'views-row',
+        'media-library-item',
+        'col-12',
+        'col-sm-6',
+        'col-md-4',
+        'col-lg-3',
+        'gy-3',
+    ]
+    %}
+    <div{{ row.attributes.addClass(row_classes) }}>
+      {{- row.content -}}
+    </div>
+  {% endfor %}
+</div>
diff --git a/templates/overrides/views/views-mini-pager.html.twig b/templates/views/views-mini-pager.html.twig
similarity index 85%
rename from templates/overrides/views/views-mini-pager.html.twig
rename to templates/views/views-mini-pager.html.twig
index 74f7fb785f9c7efc96c258bd9f9a199e625e5335..adb76f83132ba3bc880306e4cf33ae124b92807c 100644
--- a/templates/overrides/views/views-mini-pager.html.twig
+++ b/templates/views/views-mini-pager.html.twig
@@ -14,8 +14,8 @@
  */
 #}
 {% if items.previous or items.next %}
-  {{ pattern('pagination', {
-    'items': preprocessed_items,
+  {{ include('ui_suite_bootstrap:pagination', {
     'attributes': attributes.addClass('js-pager__items'),
-  }) }}
+    'items': preprocessed_items,
+  }, with_context = false) }}
 {% endif %}
diff --git a/templates/overrides/views/views-view-table.html.twig b/templates/views/views-view-table.html.twig
similarity index 69%
rename from templates/overrides/views/views-view-table.html.twig
rename to templates/views/views-view-table.html.twig
index a718ca90981019d699c3c44dff6da59555a9af12..eba24d3e88919cc86a1d13655ec2e17d38e519d2 100644
--- a/templates/overrides/views/views-view-table.html.twig
+++ b/templates/views/views-view-table.html.twig
@@ -43,12 +43,11 @@
 {% set caption_top = caption_top ? caption_top : 'false' %}
 {% set header_color = header_color ? header_color : '' %}
 
-{# @todo Remove sticky-enabled when Core 10.3 will become minimum supported version. #}
 {%
   set classes = [
   'cols-' ~ header|length,
   responsive ? 'responsive-enabled',
-  sticky ? 'sticky-enabled sticky-header',
+  sticky ? 'sticky-header',
 ]
 %}
 
@@ -86,32 +85,18 @@
       {% set active = active ?: 'is-active' in fields[key] %}
     {% endif %}
 
-    {% set column_content %}
-      {%- if column.wrapper_element -%}
-        <{{ column.wrapper_element }}>
-        {%- if column.url -%}
-          <a href="{{ column.url }}" title="{{ column.title }}" rel="nofollow">{{ column.content }}{{ column.sort_indicator }}</a>
-        {%- else -%}
-          {{ column.content }}{{ column.sort_indicator }}
-        {%- endif -%}
-        </{{ column.wrapper_element }}>
-      {%- else -%}
-        {%- if column.url -%}
-          <a href="{{ column.url }}" title="{{ column.title }}" rel="nofollow">{{ column.content }}{{ column.sort_indicator }}</a>
-        {%- else -%}
-          {{- column.content }}{{ column.sort_indicator }}
-        {%- endif -%}
-      {%- endif -%}
-    {% endset %}
-
-    {% set prepared_header = prepared_header|merge([
-      pattern('table_cell', {
+    {% set prepared_header = prepared_header|merge([{
+      '#type': 'component',
+      '#component': 'ui_suite_bootstrap:table_cell',
+      '#slots': {
+        'content': column.preparedContent,
+      },
+      '#props': {
         'attributes': column.attributes.addClass(column_classes).setAttribute('scope', 'col'),
+        'active': active,
         'tag': 'th',
-        'content': column_content,
-        'active': active
-      })
-    ]) %}
+      },
+    }]) %}
   {% endfor %}
 {% endif %}
 
@@ -136,49 +121,43 @@
       {% endfor %}
     {% endif %}
 
-    {% set column_content %}
-      {%- if column.wrapper_element -%}
-        <{{ column.wrapper_element }}>
-        {% for content in column.content %}
-          {{ content.separator }}{{ content.field_output }}
-        {% endfor %}
-        </{{ column.wrapper_element }}>
-      {%- else -%}
-        {% for content in column.content %}
-          {{- content.separator }}{{ content.field_output -}}
-        {% endfor %}
-      {%- endif %}
-    {% endset %}
-
-    {% set prepared_columns = prepared_columns|merge([
-      pattern('table_cell', {
+    {% set prepared_columns = prepared_columns|merge([{
+      '#type': 'component',
+      '#component': 'ui_suite_bootstrap:table_cell',
+      '#slots': {
+        'content': column.preparedContent,
+      },
+      '#props': {
         'attributes': column.attributes.addClass(column_classes),
-        'content': column_content,
-        'active': active
-      })
-    ]) %}
+        'active': active,
+      },
+    }]) %}
   {% endfor %}
 
-  {% set prepared_rows = prepared_rows|merge([
-    pattern('table_row', {
+  {% set prepared_rows = prepared_rows|merge([{
+    '#type': 'component',
+    '#component': 'ui_suite_bootstrap:table_row',
+    '#slots': {
+      'cells': prepared_columns,
+    },
+    '#props': {
       'attributes': row.attributes,
-      'cells': prepared_columns
-    })
-   ]) %}
+    },
+  }]) %}
 {% endfor %}
 
-{{ pattern('table', {
-  variant: 'default',
+{{ include('ui_suite_bootstrap:table', {
+  caption: caption,
+  header: prepared_header,
+  rows: prepared_rows,
   attributes: attributes.addClass(classes),
+  variant: 'default',
   header_color: header_color,
   stripes: stripes,
   borders: borders,
   hover: hover,
   responsive: responsive,
   divider: divider,
-  caption: caption,
   caption_top: caption_top,
-  header: prepared_header,
   header_columns: header|length,
-  rows: prepared_rows
-}) }}
+}, with_context = false) }}
diff --git a/tests/src/Kernel/ComponentValidatorTest.php b/tests/src/Kernel/ComponentValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5557ccda9eac2a9ba714fc22c71df849e53bcf3e
--- /dev/null
+++ b/tests/src/Kernel/ComponentValidatorTest.php
@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\ui_suite_bootstrap\Kernel;
+
+use Drupal\Tests\Core\Theme\Component\ComponentKernelTestBase;
+use Drupal\sdc_devel\Controller\ComponentValidatorOverview;
+
+/**
+ * Validate components.
+ *
+ * @group ui_suite_bootstrap
+ */
+class ComponentValidatorTest extends ComponentKernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'system',
+    'sdc_devel',
+    'ui_patterns',
+    'ui_patterns_library',
+    'ui_styles',
+    'ui_styles_entity_status',
+    'ui_styles_page',
+    'layout_options',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $themes = [
+    'ui_suite_bootstrap',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installConfig('system');
+  }
+
+  /**
+   * Validate components.
+   */
+  public function testComponents(): void {
+    $validatorController = new ComponentValidatorOverview(
+      $this->container->get('sdc_devel.validator'),
+      $this->container->get('plugin.manager.sdc'),
+      $this->container->get('renderer')
+    );
+    $overview = $validatorController->overview();
+
+    if (isset($overview['table']['#rows']) && !empty($overview['table']['#rows'])) {
+      $messages = [];
+      foreach ($overview['table']['#rows'] as $row) {
+        $message = [
+          $row['data'][0]->getText(),
+          $row['data'][1],
+          $row['data'][2],
+          $row['data'][3],
+          'Line ' . $row['data'][4],
+        ];
+        $messages[] = \implode(' | ', $message);
+      }
+      $this->fail(\implode(\PHP_EOL, $messages));
+    }
+    else {
+      $this->assertTrue(TRUE, 'No errors found');
+    }
+  }
+
+}
diff --git a/ui_examples/album.ui_examples.yml b/ui_examples/album.ui_examples.yml
index 0095f56ed75f718b936e8e7680b120036d7cdd7a..ba2d347895c50b24a2b1cbbd119f55cc8858fd50 100644
--- a/ui_examples/album.ui_examples.yml
+++ b/ui_examples/album.ui_examples.yml
@@ -65,43 +65,61 @@ render:
                 - btn-secondary
                 - my-2
   - 0:
-      type: "pattern"
-      id: "grid_row"
-      fields:
+      type: "component"
+      component: "ui_suite_bootstrap:grid_row"
+      slots:
         content:
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-          - type: "pattern_preview"
-            id: "card"
-            variant: "default"
-      settings:
-        with_container: true
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+          - type: "component"
+            component: "ui_suite_bootstrap:card"
+            story: "preview"
+            props:
+              variant: "default"
+      props:
+        container: container
         gutters: g-3
-        col_xs: col-12
-        col_sm: col-sm-6
-        col_md: col-md-4
+        col_xs: 12
+        col_sm: 6
+        col_md: 4
     type: "html_tag"
     tag: "div"
     attributes:
diff --git a/ui_examples/carousel.ui_examples.yml b/ui_examples/carousel.ui_examples.yml
index 86a908a4872055f7abff0cb3d526d4d719c11f54..bd246090336de55485bf8ab7ec83c5a160ace365 100644
--- a/ui_examples/carousel.ui_examples.yml
+++ b/ui_examples/carousel.ui_examples.yml
@@ -4,21 +4,19 @@ description: "Customize the navbar and carousel, then add some new components."
 links:
   - "https://getbootstrap.com/docs/5.3/examples/carousel/"
 render:
-  - type: "pattern"
-    id: "carousel"
+  - type: "component"
+    component: "ui_suite_bootstrap:carousel"
     attached:
       library:
         - ui_suite_bootstrap/example_carousel
-    settings:
+    props:
       with_indicators: true
       with_controls: true
-    fields:
+    slots:
       slides:
-        - type: "pattern"
-          id: "carousel_item"
-          settings:
-            active: true
-          fields:
+        - type: "component"
+          component: "ui_suite_bootstrap:carousel_item"
+          slots:
             image:
               theme: "image"
               uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzc3NyI+PC9yZWN0Pjwvc3ZnPgo="
@@ -44,16 +42,16 @@ render:
                   class:
                     - text-start
                 0:
-                  type: "pattern"
-                  id: "button"
-                  variant: "primary__lg"
-                  fields:
+                  type: "component"
+                  component: "ui_suite_bootstrap:button"
+                  slots:
                     label: "Sign up today"
-                  settings:
+                  props:
                     url: anchor"
-        - type: "pattern"
-          id: "carousel_item"
-          fields:
+                    variant: "primary__lg"
+        - type: "component"
+          component: "ui_suite_bootstrap:carousel_item"
+          slots:
             image:
               theme: "image"
               uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzc3NyI+PC9yZWN0Pjwvc3ZnPgo="
@@ -70,16 +68,16 @@ render:
               - type: "html_tag"
                 tag: "p"
                 0:
-                  type: "pattern"
-                  id: "button"
-                  variant: "primary__lg"
-                  fields:
+                  type: "component"
+                  component: "ui_suite_bootstrap:button"
+                  slots:
                     label: "Learn more"
-                  settings:
+                  props:
                     url: "https://example.com"
-        - type: "pattern"
-          id: "carousel_item"
-          fields:
+                    variant: "primary__lg"
+        - type: "component"
+          component: "ui_suite_bootstrap:carousel_item"
+          slots:
             image:
               theme: "image"
               uri: "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iYmQtcGxhY2Vob2xkZXItaW1nIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtaGlkZGVuPSJ0cnVlIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBzbGljZSIgZm9jdXNhYmxlPSJmYWxzZSI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iIzc3NyI+PC9yZWN0Pjwvc3ZnPgo="
@@ -105,22 +103,22 @@ render:
                   class:
                     - text-end
                 0:
-                  type: "pattern"
-                  id: "button"
-                  variant: "primary__lg"
-                  fields:
+                  type: "component"
+                  component: "ui_suite_bootstrap:button"
+                  slots:
                     label: "Browse gallery"
-                  settings:
+                  props:
+                    variant: "primary__lg"
                     url: "https://example.com"
-  - type: "pattern"
-    id: "grid_row"
+  - type: "component"
+    component: "ui_suite_bootstrap:grid_row"
     attributes:
       class:
         - marketing
-    settings:
-      with_container: true
-      col_lg: col-lg-4
-    fields:
+    props:
+      container: container
+      col_lg: 4
+    slots:
       content:
         - - theme: "image"
             uri: "data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="
@@ -141,13 +139,13 @@ render:
           - type: html_tag
             tag: "p"
             0:
-              type: "pattern"
-              id: "button"
-              variant: "secondary"
-              fields:
+              type: "component"
+              component: "ui_suite_bootstrap:button"
+              slots:
                 label: "View details »"
-              settings:
+              props:
                 url: "https://example.com"
+                variant: "secondary"
         - - theme: "image"
             uri: "data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="
             attributes:
@@ -167,13 +165,13 @@ render:
           - type: html_tag
             tag: "p"
             0:
-              type: "pattern"
-              id: "button"
-              variant: "secondary"
-              fields:
+              type: "component"
+              component: "ui_suite_bootstrap:button"
+              slots:
                 label: "View details »"
-              settings:
+              props:
                 url: "https://example.com"
+                variant: "secondary"
         - - theme: "image"
             uri: "data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="
             attributes:
@@ -193,13 +191,13 @@ render:
           - type: html_tag
             tag: "p"
             0:
-              type: "pattern"
-              id: "button"
-              variant: "secondary"
-              fields:
+              type: "component"
+              component: "ui_suite_bootstrap:button"
+              slots:
                 label: "View details »"
-              settings:
+              props:
                 url: "https://example.com"
+                variant: "secondary"
   - type: "html_tag"
     tag: "div"
     attributes:
diff --git a/ui_examples/pricing.ui_examples.yml b/ui_examples/pricing.ui_examples.yml
index 8e208ebad04f71b0334823ebf0c52421a7694642..39eb56bca6b96eab3a3802076aa1b0e966379920 100755
--- a/ui_examples/pricing.ui_examples.yml
+++ b/ui_examples/pricing.ui_examples.yml
@@ -29,26 +29,25 @@ render:
         class:
           - fs-5
           - text-muted
-  - type: "pattern"
-    id: "grid_row"
+  - type: "component"
+    component: "ui_suite_bootstrap:grid_row"
     attributes:
       class:
         - mb-3
         - text-center
-    settings:
-      with_container: false
-      col_xs: col-12
-      col_md: col-md-4
-    fields:
+    props:
+      col_xs: 12
+      col_md: 4
+    slots:
       content:
-        - type: "pattern"
-          id: "card"
+        - type: "component"
+          component: "ui_suite_bootstrap:card"
           attributes:
             class:
               - mb-4
               - shadow-sm
               - rounded-3
-          fields:
+          slots:
             header:
               type: "html_tag"
               tag: "h4"
@@ -105,22 +104,23 @@ render:
                       tag: "li"
                       value: "Help center access"
                   2:
-                    type: "pattern"
-                    id: "button"
-                    variant: "outline_primary__lg"
+                    type: "component"
+                    component: "ui_suite_bootstrap:button"
                     attributes:
                       class:
                         - w-100
-                    fields:
+                    slots:
                       label: "Sign up for free"
-        - type: "pattern"
-          id: "card"
+                    props:
+                      variant: "outline_primary__lg"
+        - type: "component"
+          component: "ui_suite_bootstrap:card"
           attributes:
             class:
               - mb-4
               - shadow-sm
               - rounded-3
-          fields:
+          slots:
             header:
               type: "html_tag"
               tag: "h4"
@@ -177,23 +177,24 @@ render:
                       tag: "li"
                       value: "Help center access"
                   2:
-                    type: "pattern"
-                    id: "button"
-                    variant: "primary__lg"
+                    type: "component"
+                    component: "ui_suite_bootstrap:button"
                     attributes:
                       class:
                         - w-100
-                    fields:
+                    slots:
                       label: "Get started"
-        - type: "pattern"
-          id: "card"
+                    props:
+                      variant: "primary__lg"
+        - type: "component"
+          component: "ui_suite_bootstrap:card"
           attributes:
             class:
               - mb-4
               - shadow-sm
               - rounded-3
               - border-primary
-          fields:
+          slots:
             header:
               type: "html_tag"
               tag: "h4"
@@ -250,11 +251,12 @@ render:
                       tag: "li"
                       value: "Help center access"
                   2:
-                    type: "pattern"
-                    id: "button"
-                    variant: "primary__lg"
+                    type: "component"
+                    component: "ui_suite_bootstrap:button"
                     attributes:
                       class:
                         - w-100
-                    fields:
+                    slots:
                       label: "Contact us"
+                    props:
+                      variant: "primary__lg"
diff --git a/ui_suite_bootstrap.info.yml b/ui_suite_bootstrap.info.yml
index 75e6d6b0b015dcf89b2f758ecc55270bda511232..79e0d30df860c909473f2c5f8da5e4a7ee82cdc9 100644
--- a/ui_suite_bootstrap.info.yml
+++ b/ui_suite_bootstrap.info.yml
@@ -1,12 +1,11 @@
 name: 'UI Suite Bootstrap'
 type: theme
 description: "A site-builder friendly Bootstrap theme, using the UI Suite modules."
-core_version_requirement: ^10.2 || ^11
+core_version_requirement: ^10.3.4 || ^11
 base theme: false
 dependencies:
   - layout_options:layout_options
-  - ui_patterns:ui_patterns_library
-  - ui_patterns_settings:ui_patterns_settings (>=8.x-2.2 || >=3.0)
+  - ui_patterns:ui_patterns
   - ui_styles:ui_styles
 
 regions:
@@ -32,8 +31,30 @@ libraries-override:
   core/drupal.active-link:
     js:
       misc/active-link.js: assets/js/misc/active-link.js
+  core/drupal.dialog.off_canvas:
+    css:
+      base:
+        misc/dialog/off-canvas/css/reset.css: false
+        misc/dialog/off-canvas/css/base.css: false
+        misc/dialog/off-canvas/css/utility.css: false
+      component:
+        misc/dialog/off-canvas/css/button.css: false
+        misc/dialog/off-canvas/css/drupal.css: false
+        misc/dialog/off-canvas/css/form.css: false
+        misc/dialog/off-canvas/css/table.css: false
+        misc/dialog/off-canvas/css/details.css: false
+        misc/dialog/off-canvas/css/messages.css: false
+        misc/dialog/off-canvas/css/tabledrag.css: false
+        misc/dialog/off-canvas/css/throbber.css: false
+        misc/dialog/off-canvas/css/dropbutton.css: false
+        misc/dialog/off-canvas/css/titlebar.css: false
+        misc/dialog/off-canvas/css/wrapper.css: false
   core/drupal.dropbutton: false
   core/drupal.tableheader: false
+  layout_builder/drupal.layout_builder:
+    css:
+      theme:
+        css/off-canvas.css: false
   text/drupal.text: ui_suite_bootstrap/drupal.text
   clientside_validation_jquery/cv.jquery.ife: false
   commerce_cart/cart_block: false
@@ -58,9 +79,11 @@ libraries-extend:
     - ui_suite_bootstrap/drupal.progress
   core/drupal.tabledrag:
     - ui_suite_bootstrap/drupal.tabledrag
-  system/base:
-    # @todo To remove when Core 10.3 will become minimum supported version.
-    - ui_suite_bootstrap/drupal.tabledrag
+  media_library/view:
+    - ui_suite_bootstrap/media_library.theme
+  media_library/widget:
+    - ui_suite_bootstrap/media_library.theme
+    - ui_suite_bootstrap/media_library.widget
   user/drupal.user:
     - ui_suite_bootstrap/drupal.user
   clientside_validation_jquery/cv.jquery.validate:
diff --git a/ui_suite_bootstrap.layouts.yml b/ui_suite_bootstrap.layouts.yml
index 340a15c538a565253ece7ab9997cbdcedf13a388..b73fb096552fef7508eb87d7bbae87cd12abb0b7 100644
--- a/ui_suite_bootstrap.layouts.yml
+++ b/ui_suite_bootstrap.layouts.yml
@@ -1,9 +1,10 @@
 bootstrap_grid_row_1:
-  label: "Grid row (1 col) [Bootstrap]"
+  label: "Grid row (1 col) [Bootstrap] (deprecated)"
+  description: "Deprecated in UI Suite Bootstrap 5.1.x will be removed in UI Suite Bootstrap 5.2.x or 6.0.x."
   path: templates
   template: layout--grid
   class: '\Drupal\layout_options\Plugin\Layout\LayoutOptions'
-  category: "Columns: 1"
+  category: "Deprecated"
   default_region: main
   icon_map:
     - [main]
@@ -12,11 +13,12 @@ bootstrap_grid_row_1:
       label: Main
 
 bootstrap_grid_row_2:
-  label: "Grid row (2 cols) [Bootstrap]"
+  label: "Grid row (2 cols) [Bootstrap] (deprecated)"
+  description: "Deprecated in UI Suite Bootstrap 5.1.x will be removed in UI Suite Bootstrap 5.2.x or 6.0.x."
   path: templates
   template: layout--grid
   class: '\Drupal\layout_options\Plugin\Layout\LayoutOptions'
-  category: "Columns: 2"
+  category: "Deprecated"
   default_region: main
   icon_map:
     - [main, second]
@@ -27,11 +29,12 @@ bootstrap_grid_row_2:
       label: Second
 
 bootstrap_grid_row_3:
-  label: "Grid row (3 cols) [Bootstrap]"
+  label: "Grid row (3 cols) [Bootstrap] (deprecated)"
+  description: "Deprecated in UI Suite Bootstrap 5.1.x will be removed in UI Suite Bootstrap 5.2.x or 6.0.x."
   path: templates
   template: layout--grid
   class: '\Drupal\layout_options\Plugin\Layout\LayoutOptions'
-  category: "Columns: 3"
+  category: "Deprecated"
   default_region: main
   icon_map:
     - [main, second, third]
@@ -44,11 +47,12 @@ bootstrap_grid_row_3:
       label: Third
 
 bootstrap_grid_row_4:
-  label: "Grid row (4 cols) [Bootstrap]"
+  label: "Grid row (4 cols) [Bootstrap] (deprecated)"
+  description: "Deprecated in UI Suite Bootstrap 5.1.x will be removed in UI Suite Bootstrap 5.2.x or 6.0.x."
   path: templates
   template: layout--grid
   class: '\Drupal\layout_options\Plugin\Layout\LayoutOptions'
-  category: "Columns: 4"
+  category: "Deprecated"
   default_region: main
   icon_map:
     - [main, second, third, fourth]
diff --git a/ui_suite_bootstrap.libraries.yml b/ui_suite_bootstrap.libraries.yml
index 3d468505f203a90ae628f0a0726c83d5ba307b75..6117e950a03e65e3a109473f2a40f0598f60c7f7 100644
--- a/ui_suite_bootstrap.libraries.yml
+++ b/ui_suite_bootstrap.libraries.yml
@@ -52,10 +52,15 @@ drupal.dialog.ajax:
     - core/drupal.ajax
 
 drupal.dialog.off_canvas:
+  js:
+    assets/js/misc/dialog/dialog.off-canvas.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
+    - core/drupalSettings
   css:
     component:
-      assets/css/form/off-canvas.button.css: {}
-      assets/css/form/off-canvas.form.css: {}
+      assets/css/component/off-canvas.css: {}
 
 drupal.message:
   js:
@@ -113,3 +118,14 @@ jquery.validate:
     assets/js/jquery-validation/validate.js: {}
   dependencies:
     - core/jquery
+
+media_library.theme:
+  css:
+    theme:
+      assets/css/media-library/media-library-buttons.css: {}
+      assets/css/media-library/media-library-states.css: {}
+
+media_library.widget:
+  css:
+    theme:
+      assets/css/media-library/media-library-container-query.css: {}
diff --git a/ui_suite_bootstrap.theme b/ui_suite_bootstrap.theme
index f271afc1af28dfb7d564033b8942e9cbf6f99986..2496d564c12d0f40bde1607038e99b56b4bab8fc 100644
--- a/ui_suite_bootstrap.theme
+++ b/ui_suite_bootstrap.theme
@@ -11,16 +11,17 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\ui_suite_bootstrap\HookHandler\ElementInfoAlter;
 use Drupal\ui_suite_bootstrap\HookHandler\FormAlter;
 use Drupal\ui_suite_bootstrap\HookHandler\FormCommerceCheckoutFlowMultistepDefaultAlter;
+use Drupal\ui_suite_bootstrap\HookHandler\FormMediaLibraryAddFormAlter;
 use Drupal\ui_suite_bootstrap\HookHandler\FormSearchBlockFormAlter;
-use Drupal\ui_suite_bootstrap\HookHandler\PreprocessBreadcrumb;
+use Drupal\ui_suite_bootstrap\HookHandler\FormViewsExposedFormAlter;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessDetailsAccordion;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessFieldset;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessFilterTips;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessInput;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessLinksDropbutton;
+use Drupal\ui_suite_bootstrap\HookHandler\PreprocessLinksMediaLibraryMenu;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessMaintenancePage;
-use Drupal\ui_suite_bootstrap\HookHandler\PreprocessMenu;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessMenuLocalAction;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessMenuLocalTasks;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessPage;
@@ -28,8 +29,11 @@ use Drupal\ui_suite_bootstrap\HookHandler\PreprocessPager;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessSelect;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessTextarea;
 use Drupal\ui_suite_bootstrap\HookHandler\PreprocessViewsMiniPager;
+use Drupal\ui_suite_bootstrap\HookHandler\PreprocessViewsViewTable;
 use Drupal\ui_suite_bootstrap\HookHandler\ThemeSuggestionsAlter;
+use Drupal\ui_suite_bootstrap\HookHandler\ViewsPreRender;
 use Drupal\ui_suite_bootstrap\UiSkins;
+use Drupal\views\ViewExecutable;
 
 /**
  * Implements hook_element_info_alter().
@@ -61,6 +65,15 @@ function ui_suite_bootstrap_form_commerce_checkout_flow_multistep_default_alter(
   $instance->alter($form, $form_state, $form_id);
 }
 
+/**
+ * Implements hook_form_BASE_FORM_ID_alter() for 'media_library_add_form'.
+ */
+function ui_suite_bootstrap_form_media_library_add_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\FormMediaLibraryAddFormAlter $instance */
+  $instance = \Drupal::service('class_resolver')->getInstanceFromDefinition(FormMediaLibraryAddFormAlter::class);
+  $instance->alter($form, $form_state, $form_id);
+}
+
 /**
  * Implements hook_form_FORM_ID_alter() for 'search_block_form'.
  */
@@ -72,13 +85,13 @@ function ui_suite_bootstrap_form_search_block_form_alter(array &$form, FormState
 }
 
 /**
- * Implements hook_preprocess_HOOK() for 'breadcrumb'.
+ * Implements hook_form_FORM_ID_alter() for 'views_exposed_form'.
  */
-function ui_suite_bootstrap_preprocess_breadcrumb(array &$variables): void {
-  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessBreadcrumb $instance */
+function ui_suite_bootstrap_form_views_exposed_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\FormViewsExposedFormAlter $instance */
   $instance = \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(PreprocessBreadcrumb::class);
-  $instance->preprocess($variables);
+    ->getInstanceFromDefinition(FormViewsExposedFormAlter::class);
+  $instance->alter($form, $form_state, $form_id);
 }
 
 /**
@@ -156,22 +169,22 @@ function ui_suite_bootstrap_preprocess_links__dropbutton(array &$variables): voi
 }
 
 /**
- * Implements hook_preprocess_HOOK() for 'maintenance_page'.
+ * Implements hook_preprocess_HOOK() for 'links__media_library_menu'.
  */
-function ui_suite_bootstrap_preprocess_maintenance_page(array &$variables): void {
-  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessMaintenancePage $instance */
+function ui_suite_bootstrap_preprocess_links__media_library_menu(array &$variables): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessLinksMediaLibraryMenu $instance */
   $instance = \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(PreprocessMaintenancePage::class);
+    ->getInstanceFromDefinition(PreprocessLinksMediaLibraryMenu::class);
   $instance->preprocess($variables);
 }
 
 /**
- * Implements hook_preprocess_HOOK() for 'menu'.
+ * Implements hook_preprocess_HOOK() for 'maintenance_page'.
  */
-function ui_suite_bootstrap_preprocess_menu(array &$variables): void {
-  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessMenu $instance */
+function ui_suite_bootstrap_preprocess_maintenance_page(array &$variables): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessMaintenancePage $instance */
   $instance = \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(PreprocessMenu::class);
+    ->getInstanceFromDefinition(PreprocessMaintenancePage::class);
   $instance->preprocess($variables);
 }
 
@@ -245,6 +258,16 @@ function ui_suite_bootstrap_preprocess_views_mini_pager(array &$variables): void
   $instance->preprocess($variables);
 }
 
+/**
+ * Implements hook_preprocess_HOOK() for 'views_view_table'.
+ */
+function ui_suite_bootstrap_preprocess_views_view_table(array &$variables): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\PreprocessViewsViewTable $instance */
+  $instance = \Drupal::service('class_resolver')
+    ->getInstanceFromDefinition(PreprocessViewsViewTable::class);
+  $instance->preprocess($variables);
+}
+
 /**
  * Implements hook_theme_suggestions_HOOK_alter() for 'details'.
  */
@@ -264,3 +287,13 @@ function ui_suite_bootstrap_theme_suggestions_input_alter(array &$suggestions, a
     ->getInstanceFromDefinition(ThemeSuggestionsAlter::class);
   $instance->input($suggestions, $variables);
 }
+
+/**
+ * Implements hook_views_pre_render().
+ */
+function ui_suite_bootstrap_views_pre_render(ViewExecutable $view): void {
+  /** @var \Drupal\ui_suite_bootstrap\HookHandler\ViewsPreRender $instance */
+  $instance = \Drupal::service('class_resolver')
+    ->getInstanceFromDefinition(ViewsPreRender::class);
+  $instance->preRender($view);
+}