diff --git a/.drone.yml b/.drone.yml
index 9c0a924135fee896c7a8aaf16549328e2ac0fc4d..3d2855f4fbc48569d0b1ea6a0c746a37c4292785 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -102,6 +102,7 @@ pipeline:
       event: tag
       matrix:
         COMPOSER_BOUNDARY: highest
+        PHP_VERSION: 7.4
 
   github-release:
     image: registry.fpfis.eu/drone-plugins/github-release
@@ -113,6 +114,7 @@ pipeline:
       event: tag
       matrix:
         COMPOSER_BOUNDARY: highest
+        PHP_VERSION: 7.4
 
 matrix:
   COMPOSER_BOUNDARY:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdc8aeb2683e23cd51d34c21d3fc2e2e893f5921..b0aaca79cb038377950f07afa58483840285d67f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,41 @@
 # Change Log
 
+## [1.0.0-alpha7](https://github.com/openeuropa/oe_whitelabel/tree/1.0.0-alpha7) (2022-04-08)
+[Full Changelog](https://github.com/openeuropa/oe_whitelabel/compare/1.0.0-alpha6...1.0.0-alpha7)
+
+**Merged pull requests:**
+
+- OEL-1434: Filter out bundles if no legacy fields present [\#119](https://github.com/openeuropa/oe_whitelabel/pull/119) ([abel-santos-corral](https://github.com/abel-santos-corral))
+
+## [1.0.0-alpha6](https://github.com/openeuropa/oe_whitelabel/tree/1.0.0-alpha6) (2022-04-07)
+[Full Changelog](https://github.com/openeuropa/oe_whitelabel/compare/1.0.0-alpha5...1.0.0-alpha6)
+
+**Closed issues:**
+
+- Remove the dependency on oe\_multilingual from oe\_whitelabel\_helper [\#32](https://github.com/openeuropa/oe_whitelabel/issues/32)
+
+**Merged pull requests:**
+
+- Prepare release 1.0.0-alpha6 [\#117](https://github.com/openeuropa/oe_whitelabel/pull/117) ([abel-santos-corral](https://github.com/abel-santos-corral))
+- OEL-0000: Prepare oe\_whitelabel release packages only once. [\#114](https://github.com/openeuropa/oe_whitelabel/pull/114) ([escuriola](https://github.com/escuriola))
+- OEL-1159: Adapt starter content entities to card last changes. [\#112](https://github.com/openeuropa/oe_whitelabel/pull/112) ([escuriola](https://github.com/escuriola))
+- OEL-494: Style document paragraph. [\#108](https://github.com/openeuropa/oe_whitelabel/pull/108) ([brummbar](https://github.com/brummbar))
+- OEL-0000: Improve News & Event teaser templates [\#106](https://github.com/openeuropa/oe_whitelabel/pull/106) ([drishu](https://github.com/drishu))
+- EPIC: OEL-1255: Migrate paragraphs [\#105](https://github.com/openeuropa/oe_whitelabel/pull/105) ([donquixote](https://github.com/donquixote))
+- OEL-1322: Upgrade oe\_whitelabel to PHP 8.0. [\#98](https://github.com/openeuropa/oe_whitelabel/pull/98) ([escuriola](https://github.com/escuriola))
+- OEL-0000: Fix broken two column layout [\#96](https://github.com/openeuropa/oe_whitelabel/pull/96) ([drishu](https://github.com/drishu))
+- OEL-1167: Theme the content language switcher [\#94](https://github.com/openeuropa/oe_whitelabel/pull/94) ([GilNovacomm](https://github.com/GilNovacomm))
+- OEL-1291: News and Event content types renamed. [\#92](https://github.com/openeuropa/oe_whitelabel/pull/92) ([Maxfire](https://github.com/Maxfire))
+- OEL-1307: Update oe\_whitelabel to BCL 0.20.0 [\#91](https://github.com/openeuropa/oe_whitelabel/pull/91) ([escuriola](https://github.com/escuriola))
+- OEL-1147 - Footer [\#81](https://github.com/openeuropa/oe_whitelabel/pull/81) ([escuriola](https://github.com/escuriola))
+- OEL-1160: Header refactor. [\#71](https://github.com/openeuropa/oe_whitelabel/pull/71) ([escuriola](https://github.com/escuriola))
+
 ## [1.0.0-alpha5](https://github.com/openeuropa/oe_whitelabel/tree/1.0.0-alpha5) (2022-03-10)
 [Full Changelog](https://github.com/openeuropa/oe_whitelabel/compare/1.0.0-alpha4...1.0.0-alpha5)
 
 **Merged pull requests:**
 
+- Prepare release 1.0.0-alpha5 [\#90](https://github.com/openeuropa/oe_whitelabel/pull/90) ([abel-santos-corral](https://github.com/abel-santos-corral))
 - OEL-1286: Composer modified for bootstrap theme release. [\#88](https://github.com/openeuropa/oe_whitelabel/pull/88) ([Maxfire](https://github.com/Maxfire))
 - OEL-1239: Update bootstrap release. [\#87](https://github.com/openeuropa/oe_whitelabel/pull/87) ([GilNovacomm](https://github.com/GilNovacomm))
 - OEL-1241: No margin in search box input field. [\#86](https://github.com/openeuropa/oe_whitelabel/pull/86) ([escuriola](https://github.com/escuriola))
diff --git a/README.md b/README.md
index a223d5cb1f4f7e6a6fa653b1e8ad534c3e300a50..b354238d3beb741e7e3fe8caa0b05c72a53056c7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,17 @@
 # The OpenEuropa Whitelabel theme
 
+## Paragraphs
+
+The paragraphs below are not yet themed therefore not recommended for usage:
+
+- Contextual navigation
+- Document
+
+Some paragraphs are considered "internal", and only meant to be used inside other paragraphs:
+
+- Listing item: To be used as item paragraph within 'Listing item block'.
+- Fact: To be used as item paragraph within 'Facts and figures'.
+
 ## Requirements
 
 This depends on the following software:
@@ -18,7 +30,13 @@ composer require openeuropa/oe_whitelabel
 
 In order to enable the theme in your project perform the following steps:
 
-- Enable the OpenEuropa Whitelabel Theme and set it as default ```./vendor/bin/drush config-set system.theme default oe_bootstrap_theme```
+- Enable the OpenEuropa Whitelabel Theme and set it as default ```./vendor/bin/drush config-set system.theme default oe_whitelabel_theme```
+
+### Integration with oe_paragraphs
+
+In order to have full working integration with paragraphs in your project, you must enable oe_whitelabel_paragraphs module:
+
+```./vendor/bin/drush en oe_whitelabel_paragraphs```
 
 ## Development setup
 
@@ -129,3 +147,29 @@ To run the phpunit tests:
 ```bash
 docker-compose exec web ./vendor/bin/phpunit
 ```
+
+## Upgrade from older versions
+
+### Upgrade to 1.0.0-alpha7
+
+#### Paragraphs migration
+
+Paragraphs-related theming and functionality has been moved from the [OpenEuropa Bootstrap base theme](https://github.com/openeuropa/oe_bootstrap_theme) to [OpenEuropa Whitelabel](https://github.com/openeuropa/oe_whitelabel).
+
+Special paragraphs fields that were introduced in `oe_bootstrap_theme_paragraphs` are being renamed in `oe_whitelabel_paragraphs`.
+
+If you have the `oe_paragraphs` module enabled, you should create a `hook_post_update_NAME()` in your code, to enable the `oe_whitelabel_paragraphs` module during deployment.
+
+```php
+function EXAMPLE_post_update_00001(): void {
+  \Drupal::service('module_installer')->install(['oe_whitelabel_paragraphs']);
+}
+```
+
+This is needed to make sure that the install hook for `oe_whitelabel_paragraphs` runs _before_ config-import during a deployment.
+
+Note that `drush updb` will also trigger update hooks in `oe_bootstrap_theme_helper`, which will uninstall the legacy module `oe_bootstrap_theme_paragraphs`.
+
+### Upgrade to 1.0.0-alpha6
+
+This release contains some bugs, please move directly to alpha7.
diff --git a/composer.json b/composer.json
index f75b7a11e9326e3a4940ed02c8a100ce4777e2bc..0eeb78e85afa8b28d09736b690dfc71825dfe825 100644
--- a/composer.json
+++ b/composer.json
@@ -10,7 +10,7 @@
         "cweagans/composer-patches": "^1.7",
         "drupal/core": "^9.2",
         "drupal/twig_field_value": "^2.0",
-        "openeuropa/oe_bootstrap_theme": "0.1.202203290731"
+        "openeuropa/oe_bootstrap_theme": "1.0.0-alpha8"
     },
     "require-dev": {
         "composer/installers": "^1.11",
@@ -20,10 +20,11 @@
         "drupal/core-composer-scaffold": "^9.2",
         "drupal/core-dev": "^9.2",
         "drupal/ctools": "^3.7",
+        "drupal/description_list_field": "^1.0@alpha",
         "drupal/drupal-extension": "~4.1",
         "drupal/entity_reference_revisions": "^1.9",
         "drupal/field_group": "^3.2",
-        "drupal/file_link": "^2.0.4",
+        "drupal/file_link": "^2.0.6",
         "drupal/pathauto": "^1.8",
         "drupal/search_api": "^1.21",
         "drupal/search_api_autocomplete": "^1.5",
@@ -41,7 +42,9 @@
         "openeuropa/oe_content": "^2.8.0",
         "openeuropa/oe_content_extra": "dev-EPIC-1293-Project",
         "openeuropa/oe_corporate_blocks": "^4.4",
+        "openeuropa/oe_media": "^1.14",
         "openeuropa/oe_multilingual": "^1.9",
+        "openeuropa/oe_paragraphs": "^1.13",
         "openeuropa/oe_starter_content": "1.x-dev",
         "openeuropa/task-runner-drupal-project-symlink": "^1.0-beta5",
         "phpspec/prophecy-phpunit": "^1 || ^2",
@@ -65,9 +68,15 @@
             "url": "https://github.com/openeuropa/oe_content_extra"
         }
     },
+    "autoload": {
+        "psr-4": {
+            "Drupal\\oe_whitelabel\\": "./src/"
+        }
+    },
     "autoload-dev": {
         "psr-4": {
-            "Drupal\\Tests\\oe_whitelabel\\": "./tests/src/"
+            "Drupal\\Tests\\oe_whitelabel\\": "./tests/src/",
+            "Drupal\\Tests\\oe_bootstrap_theme\\": "./build/themes/contrib/oe_bootstrap_theme/tests/src/"
         }
     },
     "extra": {
diff --git a/includes/paragraphs.inc b/includes/paragraphs.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5e2d923ad7a3aad721a432eed159156fa85b07cd
--- /dev/null
+++ b/includes/paragraphs.inc
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Theme functions for paragraphs.
+ */
+
+declare(strict_types = 1);
+
+/**
+ * Implements hook_theme_suggestions_HOOK_alter().
+ */
+function oe_whitelabel_theme_suggestions_paragraph_alter(array &$suggestions, array $variables): void {
+  /** @var \Drupal\paragraphs\ParagraphInterface $paragraph */
+  $paragraph = $variables['elements']['#paragraph'];
+
+  if ($paragraph->bundle() === 'oe_content_row') {
+    $variant = $paragraph->get('oe_paragraphs_variant')->first()->value;
+    $suggestions[] = 'paragraph__' . $paragraph->bundle() . '__variant_' . $variant;
+  }
+}
diff --git a/modules/oe_whitelabel_extra_project/oe_whitelabel_extra_project.module b/modules/oe_whitelabel_extra_project/oe_whitelabel_extra_project.module
index 98ad2985ff43efe5c9260b09ca710e8cb7f1b9c0..d0cf9fe4220d0775583fa2f0d89f60b0b4a944db 100644
--- a/modules/oe_whitelabel_extra_project/oe_whitelabel_extra_project.module
+++ b/modules/oe_whitelabel_extra_project/oe_whitelabel_extra_project.module
@@ -54,9 +54,6 @@ function oe_whitelabel_extra_project_preprocess_node__oe_project(&$variables) {
   if ($variables['view_mode'] === 'full') {
     _oe_whitelabel_extra_project_preprocess_inpage_nav($variables);
   }
-  if ($variables['view_mode'] === 'teaser') {
-    _oe_whitelabel_extra_project_preprocess_badges($variables);
-  }
 }
 
 /**
@@ -105,16 +102,10 @@ function _oe_whitelabel_extra_project_preprocess_featured_media(&$variables) {
     return;
   }
 
+  /** @var \Drupal\image\Plugin\Field\FieldType\ImageItem $thumbnail */
   $thumbnail = $media->get('thumbnail')->first();
   $variables['image'] = ImageValueObject::fromImageItem($thumbnail);
 
-  // @todo Remove once the OEL-1159 issue is resolved.
-  if ($variables['view_mode'] == 'teaser') {
-    $variables['image'] = [
-      '#markup' => $variables['image']->getSource(),
-    ];
-  }
-
   $cacheability->applyTo($variables);
 }
 
@@ -155,30 +146,3 @@ function _oe_whitelabel_extra_project_preprocess_inpage_nav(array &$variables):
   }
 
 }
-
-/**
- * Helper function to preprocess the project teaser badges.
- *
- * The project teaser is themed with 'card' pattern 'search' variant,
- * this expects a list of labels keyed by '#title' for the badges.
- *
- * @todo Remove once the OEL-1159 issue is resolved.
- *
- * @param array $variables
- *   Render array variables.
- */
-function _oe_whitelabel_extra_project_preprocess_badges(array &$variables): void {
-  /** @var \Drupal\node\NodeInterface $node */
-  $node = $variables['node'];
-
-  if ($node->get('oe_subject')->isEmpty()) {
-    return;
-  }
-
-  $variables['badges'] = [];
-  foreach ($node->get('oe_subject') as $item) {
-    $variables['badges'][] = [
-      '#title' => $item->entity->label(),
-    ];
-  }
-}
diff --git a/modules/oe_whitelabel_helper/oe_whitelabel_helper.install b/modules/oe_whitelabel_helper/oe_whitelabel_helper.install
new file mode 100644
index 0000000000000000000000000000000000000000..f7f14615c47f6cc5b50191f9b4560d4f4ee4c162
--- /dev/null
+++ b/modules/oe_whitelabel_helper/oe_whitelabel_helper.install
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Install and update functions for the OE Whitelabel Helper module.
+ */
+
+declare(strict_types = 1);
+
+/**
+ * Implements hook_requirements().
+ */
+function oe_whitelabel_helper_requirements($phase): array {
+  $requirements = [];
+
+  if (\Drupal::moduleHandler()->moduleExists('oe_paragraphs') && !\Drupal::moduleHandler()->moduleExists('oe_whitelabel_paragraphs')) {
+    $requirements['oe_whitelabel_paragraphs'] = [
+      'title' => 'OpenEuropa Whitelabel Paragraphs',
+      'description' => t('OpenEuropa Whitelabel Paragraphs is required if OpenEuropa Paragraphs is enabled.'),
+      'severity' => REQUIREMENT_ERROR,
+    ];
+  }
+
+  return $requirements;
+}
diff --git a/modules/oe_whitelabel_helper/src/EuropeanUnionLanguages.php b/modules/oe_whitelabel_helper/src/EuropeanUnionLanguages.php
deleted file mode 100644
index 9ac60d58512bcf24f145222c85cf20adc9fdbdd4..0000000000000000000000000000000000000000
--- a/modules/oe_whitelabel_helper/src/EuropeanUnionLanguages.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-
-declare(strict_types = 1);
-
-namespace Drupal\oe_whitelabel_helper;
-
-/**
- * Helper class storing European Union languages information.
- *
- * @see https://github.com/openeuropa/oe_theme/blob/HEAD/modules/oe_theme_helper/src/EuropeanUnionLanguages.php
- */
-class EuropeanUnionLanguages {
-
-  /**
-   * List of European Union languages.
-   *
-   * Each entry includes:
-   *
-   * - The language name in English
-   * - The language name in its native form
-   * - The internal language ID, used on URLs, asset names, etc.
-   *
-   * @var array
-   */
-  protected static $languages = [
-    'bg' => ['Bulgarian', 'български', 'bg'],
-    'cs' => ['Czech', 'čeština', 'cs'],
-    'da' => ['Danish', 'dansk', 'da'],
-    'de' => ['German', 'Deutsch', 'de'],
-    'et' => ['Estonian', 'eesti', 'et'],
-    'el' => ['Greek', 'ελληνικά', 'el'],
-    'en' => ['English', 'English', 'en'],
-    'es' => ['Spanish', 'español', 'es'],
-    'fr' => ['French', 'français', 'fr'],
-    'ga' => ['Irish', 'Gaeilge', 'ga'],
-    'hr' => ['Croatian', 'hrvatski', 'hr'],
-    'it' => ['Italian', 'italiano', 'it'],
-    'lt' => ['Lithuanian', 'lietuvių', 'lt'],
-    'lv' => ['Latvian', 'latviešu', 'lv'],
-    'hu' => ['Hungarian', 'magyar', 'hu'],
-    'mt' => ['Maltese', 'Malti', 'mt'],
-    'nl' => ['Dutch', 'Nederlands', 'nl'],
-    'pl' => ['Polish', 'polski', 'pl'],
-    'pt-pt' => ['Portuguese', 'português', 'pt'],
-    'ro' => ['Romanian', 'română', 'ro'],
-    'sk' => ['Slovak', 'slovenčina', 'sk'],
-    'sl' => ['Slovenian', 'slovenščina', 'sl'],
-    'fi' => ['Finnish', 'suomi', 'fi'],
-    'sv' => ['Swedish', 'svenska', 'sv'],
-  ];
-
-  /**
-   * Returns a list of language data.
-   *
-   * This is the data that is expected to be returned by the overridden language
-   * manager as supplied by the OpenEuropa Multilingual module.
-   *
-   * @return array
-   *   An array with language codes as keys, and English and native language
-   *   names as values.
-   */
-  public static function getLanguageList(): array {
-    return self::$languages;
-  }
-
-  /**
-   * Assert whether the given language is a European Union one.
-   *
-   * @param string $language_code
-   *   The language code as defined by the W3C language tags document.
-   *
-   * @return bool
-   *   Whereas the given language is a European Union one.
-   */
-  public static function hasLanguage(string $language_code): bool {
-    return isset(self::$languages[$language_code]);
-  }
-
-  /**
-   * Get the language name in English given its W3C code.
-   *
-   * @param string $language_code
-   *   The language code as defined by the W3C language tags document.
-   *
-   * @return string
-   *   The language name in English if any, an empty string otherwise.
-   */
-  public static function getEnglishLanguageName(string $language_code): string {
-    return self::$languages[$language_code][0] ?? '';
-  }
-
-  /**
-   * Get the native language name given its W3C code.
-   *
-   * @param string $language_code
-   *   The language code as defined by the W3C language tags document.
-   *
-   * @return string
-   *   The native language name if any, an empty string otherwise.
-   */
-  public static function getNativeLanguageName(string $language_code): string {
-    return self::$languages[$language_code][1] ?? '';
-  }
-
-  /**
-   * Get the internal language code given its W3C code.
-   *
-   * Internal language codes may differ from the standard ones.
-   *
-   * @param string $language_code
-   *   The language code as defined by the W3C language tags document.
-   *
-   * @return string
-   *   The internal language code if any, an empty string otherwise.
-   */
-  public static function getInternalLanguageCode(string $language_code): string {
-    return self::$languages[$language_code][2] ?? '';
-  }
-
-}
diff --git a/modules/oe_whitelabel_helper/src/TwigExtension/TwigExtension.php b/modules/oe_whitelabel_helper/src/TwigExtension/TwigExtension.php
index 944b17e5fa625af94525c1631f9d1a6d2eb700e2..e667825177985d5331d24f9d741dfb4a5b50f1a8 100644
--- a/modules/oe_whitelabel_helper/src/TwigExtension/TwigExtension.php
+++ b/modules/oe_whitelabel_helper/src/TwigExtension/TwigExtension.php
@@ -6,7 +6,6 @@ namespace Drupal\oe_whitelabel_helper\TwigExtension;
 
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
-use Drupal\oe_whitelabel_helper\EuropeanUnionLanguages;
 use Drupal\Core\Url;
 use Twig\Extension\AbstractExtension;
 use Twig\TwigFilter;
@@ -37,7 +36,6 @@ class TwigExtension extends AbstractExtension {
   public function getFilters(): array {
     return [
       new TwigFilter('bcl_timeago', [$this, 'bclTimeAgo']),
-      new TwigFilter('to_internal_language_id', [$this, 'toInternalLanguageId']),
     ];
   }
 
@@ -184,21 +182,4 @@ class TwigExtension extends AbstractExtension {
     return $block_plugin->build();
   }
 
-  /**
-   * Get an internal language ID given its code.
-   *
-   * @param string $language_code
-   *   The language code as defined by the W3C language tags document.
-   *
-   * @return string
-   *   The internal language ID, or the given language code if none found.
-   */
-  public function toInternalLanguageId(string $language_code): string {
-    if (EuropeanUnionLanguages::hasLanguage($language_code)) {
-      return EuropeanUnionLanguages::getInternalLanguageCode($language_code);
-    }
-
-    return $language_code;
-  }
-
 }
diff --git a/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module
index 1dc9264e18018eb5f766cd521a7382da0ec50495..85fdf74f758967d9e56ded9a7b72b1b0b8848dc5 100755
--- a/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module
+++ b/modules/oe_whitelabel_multilingual/oe_whitelabel_multilingual.module
@@ -8,7 +8,7 @@
 declare(strict_types =  1);
 
 use Drupal\Component\Utility\Html;
-use Drupal\oe_whitelabel_helper\EuropeanUnionLanguages;
+use Drupal\oe_bootstrap_theme_helper\EuropeanUnionLanguages;
 
 /**
  * Implements hook_preprocess_links().
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_description_list.oe_w_orientation.yml b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_description_list.oe_w_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1e4485067b688200c42911900ab62475a4b6bdb3
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_description_list.oe_w_orientation.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_w_orientation
+    - paragraphs.paragraphs_type.oe_description_list
+  module:
+    - options
+id: paragraph.oe_description_list.oe_w_orientation
+field_name: oe_w_orientation
+entity_type: paragraph
+bundle: oe_description_list
+label: Orientation
+description: 'Sets the orientation (vertical|horizontal) for the paragraph.'
+required: true
+translatable: false
+default_value:
+  -
+    value: horizontal
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_facts_figures.oe_w_n_columns.yml b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_facts_figures.oe_w_n_columns.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0165929a535a538b03fa540f3e04559de6f79196
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_facts_figures.oe_w_n_columns.yml
@@ -0,0 +1,24 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_w_n_columns
+    - paragraphs.paragraphs_type.oe_facts_figures
+id: paragraph.oe_facts_figures.oe_w_n_columns
+field_name: oe_w_n_columns
+entity_type: paragraph
+bundle: oe_facts_figures
+label: 'Number of columns'
+description: 'Sets the number of grid columns. Minimum number is 1 column and maximum is 3.'
+required: false
+translatable: false
+default_value:
+  -
+    value: 1
+default_value_callback: ''
+settings:
+  min: 1
+  max: 3
+  prefix: ''
+  suffix: ''
+field_type: integer
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_background.yml b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5ac9c7283d806caea21c96d50c30e23a1638478f
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_background.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_w_links_block_background
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - options
+id: paragraph.oe_links_block.oe_w_links_block_background
+field_name: oe_w_links_block_background
+entity_type: paragraph
+bundle: oe_links_block
+label: Background
+description: 'Allows to select the background color of the links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: gray
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_orientation.yml b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2b3bf721cd4d0977d63d9d4704a4de7bf6651abc
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_links_block.oe_w_links_block_orientation.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_w_links_block_orientation
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - options
+id: paragraph.oe_links_block.oe_w_links_block_orientation
+field_name: oe_w_links_block_orientation
+entity_type: paragraph
+bundle: oe_links_block
+label: Orientation
+description: 'Allows to select the direction of the links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: vertical
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_social_media_follow.oe_w_links_block_background.yml b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_social_media_follow.oe_w_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2d8fae0997a07142a7c96abde650945242f4e174
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.field.paragraph.oe_social_media_follow.oe_w_links_block_background.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_w_links_block_background
+    - paragraphs.paragraphs_type.oe_social_media_follow
+  module:
+    - options
+id: paragraph.oe_social_media_follow.oe_w_links_block_background
+field_name: oe_w_links_block_background
+entity_type: paragraph
+bundle: oe_social_media_follow
+label: Background
+description: 'Allows to select the background color of the Social Media Links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: gray
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_background.yml b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..289994964b5e648b871e282b6401cc5eea15e1c2
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_background.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_w_links_block_background
+field_name: oe_w_links_block_background
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: gray
+      label: Gray
+    -
+      value: transparent
+      label: Transparent
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_orientation.yml b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..afdf66e7c4492520eca3363e353f96de3a01728d
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_links_block_orientation.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_w_links_block_orientation
+field_name: oe_w_links_block_orientation
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: horizontal
+      label: Horizontal
+    -
+      value: vertical
+      label: Vertical
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_n_columns.yml b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_n_columns.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3a1a9cbc933ff4161eceafc3b82e011e6d27650e
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_n_columns.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - paragraphs
+id: paragraph.oe_w_n_columns
+field_name: oe_w_n_columns
+entity_type: paragraph
+type: integer
+settings:
+  unsigned: false
+  size: normal
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_orientation.yml b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f277e814004868e566513e2f99b0967d2353bc43
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/install/field.storage.paragraph.oe_w_orientation.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_w_orientation
+field_name: oe_w_orientation
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: vertical
+      label: Vertical
+    -
+      value: horizontal
+      label: Horizontal
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_accordion_item.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_accordion_item.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3b7368e64cbba5a66750ac514b72b55ba4be3d6d
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_accordion_item.default.yml
@@ -0,0 +1,36 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_accordion_item.field_oe_icon
+    - field.field.paragraph.oe_accordion_item.field_oe_text
+    - field.field.paragraph.oe_accordion_item.field_oe_text_long
+    - paragraphs.paragraphs_type.oe_accordion_item
+  module:
+    - text
+id: paragraph.oe_accordion_item.default
+targetEntityType: paragraph
+bundle: oe_accordion_item
+mode: default
+content:
+  field_oe_text:
+    weight: 0
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    region: content
+  field_oe_text_long:
+    weight: 1
+    settings:
+      rows: 5
+      placeholder: ''
+    third_party_settings: {  }
+    type: text_textarea
+    region: content
+hidden:
+  created: true
+  field_oe_icon: true
+  status: true
+  uid: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_description_list.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_description_list.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0391e2563c5e154fe620db0d956c779898120dcc
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_description_list.default.yml
@@ -0,0 +1,38 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_description_list.field_oe_description_list_items
+    - field.field.paragraph.oe_description_list.field_oe_title
+    - field.field.paragraph.oe_description_list.oe_w_orientation
+    - paragraphs.paragraphs_type.oe_description_list
+  module:
+    - description_list_field
+id: paragraph.oe_description_list.default
+targetEntityType: paragraph
+bundle: oe_description_list
+mode: default
+content:
+  field_oe_description_list_items:
+    weight: 2
+    settings: {  }
+    third_party_settings: {  }
+    type: description_list_widget
+    region: content
+  field_oe_title:
+    weight: 1
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    region: content
+  oe_w_orientation:
+    type: options_select
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden:
+  created: true
+  status: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_facts_figures.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_facts_figures.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d12c53635d2c77c6c32100fac6d0d685ededd07b
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_facts_figures.default.yml
@@ -0,0 +1,61 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_facts_figures.field_oe_link
+    - field.field.paragraph.oe_facts_figures.field_oe_paragraphs
+    - field.field.paragraph.oe_facts_figures.field_oe_title
+    - field.field.paragraph.oe_facts_figures.oe_w_n_columns
+    - paragraphs.paragraphs_type.oe_facts_figures
+  module:
+    - link
+    - oe_paragraphs
+id: paragraph.oe_facts_figures.default
+targetEntityType: paragraph
+bundle: oe_facts_figures
+mode: default
+content:
+  field_oe_link:
+    type: link_default
+    weight: 2
+    region: content
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+  field_oe_paragraphs:
+    type: oe_paragraphs_variants
+    weight: 8
+    region: content
+    settings:
+      title: Paragraph
+      title_plural: Paragraphs
+      edit_mode: open
+      add_mode: dropdown
+      form_display_mode: default
+      default_paragraph_type: ''
+      closed_mode: summary
+      autocollapse: none
+      closed_mode_threshold: 0
+      features:
+        collapse_edit_all: collapse_edit_all
+        duplicate: duplicate
+    third_party_settings: {  }
+  field_oe_title:
+    type: string_textfield
+    weight: 1
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  oe_w_n_columns:
+    weight: 6
+    settings:
+      placeholder: ''
+    third_party_settings: {  }
+    type: number
+    region: content
+hidden:
+  created: true
+  status: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_links_block.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_links_block.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0e2b032e74278f92682b0096ed2233083b517129
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_links_block.default.yml
@@ -0,0 +1,48 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_links_block.field_oe_links
+    - field.field.paragraph.oe_links_block.oe_w_links_block_background
+    - field.field.paragraph.oe_links_block.oe_w_links_block_orientation
+    - field.field.paragraph.oe_links_block.field_oe_text
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - link
+id: paragraph.oe_links_block.default
+targetEntityType: paragraph
+bundle: oe_links_block
+mode: default
+content:
+  field_oe_links:
+    weight: 3
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+    type: link_default
+    region: content
+  oe_w_links_block_background:
+    weight: 1
+    settings: {  }
+    third_party_settings: {  }
+    type: options_select
+    region: content
+  oe_w_links_block_orientation:
+    weight: 0
+    settings: {  }
+    third_party_settings: {  }
+    type: options_select
+    region: content
+  field_oe_text:
+    weight: 2
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    region: content
+hidden:
+  created: true
+  status: true
+  uid: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a80ab7071e5dce0520213b47ff64699517e6fc23
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item.default.yml
@@ -0,0 +1,71 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_list_item.field_oe_date
+    - field.field.paragraph.oe_list_item.field_oe_image
+    - field.field.paragraph.oe_list_item.field_oe_link
+    - field.field.paragraph.oe_list_item.field_oe_meta
+    - field.field.paragraph.oe_list_item.field_oe_text_long
+    - field.field.paragraph.oe_list_item.field_oe_title
+    - image.style.thumbnail
+    - paragraphs.paragraphs_type.oe_list_item
+  module:
+    - allowed_formats
+    - image
+    - link
+    - text
+id: paragraph.oe_list_item.default
+targetEntityType: paragraph
+bundle: oe_list_item
+mode: default
+content:
+  field_oe_image:
+    type: image_image
+    weight: 3
+    region: content
+    settings:
+      progress_indicator: throbber
+      preview_image_style: thumbnail
+    third_party_settings: {  }
+  field_oe_link:
+    type: link_default
+    weight: 0
+    region: content
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+  field_oe_meta:
+    type: string_textfield
+    weight: 4
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  field_oe_text_long:
+    type: text_textarea
+    weight: 2
+    region: content
+    settings:
+      rows: 3
+      placeholder: ''
+    third_party_settings:
+      allowed_formats:
+        hide_help: '1'
+        hide_guidelines: '1'
+  field_oe_title:
+    type: string_textfield
+    weight: 1
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+hidden:
+  created: true
+  field_oe_date: true
+  status: true
+  translation: true
+  uid: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6497f1fd68ed773d1041bb78ecfd57d63cc1bc91
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.default.yml
@@ -0,0 +1,67 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_list_item_block.field_oe_link
+    - field.field.paragraph.oe_list_item_block.field_oe_list_item_block_layout
+    - field.field.paragraph.oe_list_item_block.field_oe_paragraphs
+    - field.field.paragraph.oe_list_item_block.field_oe_title
+    - paragraphs.paragraphs_type.oe_list_item_block
+  module:
+    - link
+    - paragraphs
+id: paragraph.oe_list_item_block.default
+targetEntityType: paragraph
+bundle: oe_list_item_block
+mode: default
+content:
+  field_oe_link:
+    type: link_default
+    weight: 3
+    region: content
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+  field_oe_list_item_block_layout:
+    type: options_select
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_oe_paragraphs:
+    type: paragraphs
+    weight: 2
+    region: content
+    settings:
+      title: Paragraph
+      title_plural: Paragraphs
+      edit_mode: closed
+      closed_mode: summary
+      autocollapse: none
+      closed_mode_threshold: 0
+      add_mode: dropdown
+      form_display_mode: default
+      default_paragraph_type: oe_list_item
+      features:
+        add_above: '0'
+        collapse_edit_all: collapse_edit_all
+        duplicate: duplicate
+    third_party_settings: {  }
+  field_oe_title:
+    type: string_textfield
+    weight: 1
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  translation:
+    weight: 4
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden:
+  created: true
+  status: true
+  uid: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.highlight.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.highlight.yml
new file mode 100644
index 0000000000000000000000000000000000000000..28e0a334f75d1213de8a45ffd1edc543d710b3fe
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_list_item_block.highlight.yml
@@ -0,0 +1,68 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_form_mode.paragraph.highlight
+    - field.field.paragraph.oe_list_item_block.field_oe_link
+    - field.field.paragraph.oe_list_item_block.field_oe_list_item_block_layout
+    - field.field.paragraph.oe_list_item_block.field_oe_paragraphs
+    - field.field.paragraph.oe_list_item_block.field_oe_title
+    - paragraphs.paragraphs_type.oe_list_item_block
+  module:
+    - link
+    - paragraphs
+id: paragraph.oe_list_item_block.highlight
+targetEntityType: paragraph
+bundle: oe_list_item_block
+mode: highlight
+content:
+  field_oe_link:
+    type: link_default
+    weight: 3
+    region: content
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+  field_oe_list_item_block_layout:
+    type: options_select
+    weight: 0
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_oe_paragraphs:
+    type: paragraphs
+    weight: 2
+    region: content
+    settings:
+      title: Paragraph
+      title_plural: Paragraphs
+      edit_mode: closed
+      closed_mode: summary
+      autocollapse: none
+      closed_mode_threshold: 0
+      add_mode: dropdown
+      form_display_mode: highlight
+      default_paragraph_type: oe_list_item
+      features:
+        add_above: '0'
+        collapse_edit_all: collapse_edit_all
+        duplicate: duplicate
+    third_party_settings: {  }
+  field_oe_title:
+    type: string_textfield
+    weight: 1
+    region: content
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+  translation:
+    weight: 4
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+hidden:
+  created: true
+  status: true
+  uid: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_social_media_follow.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_social_media_follow.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..95a3846901360edb5e74ae1e74add620785ad8db
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_form_display.paragraph.oe_social_media_follow.default.yml
@@ -0,0 +1,57 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_social_media_follow.oe_w_links_block_background
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_links
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_see_more
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant
+    - field.field.paragraph.oe_social_media_follow.field_oe_title
+    - paragraphs.paragraphs_type.oe_social_media_follow
+  module:
+    - link
+    - typed_link
+id: paragraph.oe_social_media_follow.default
+targetEntityType: paragraph
+bundle: oe_social_media_follow
+mode: default
+content:
+  oe_w_links_block_background:
+    type: options_select
+    weight: 1
+    region: content
+    settings: {  }
+    third_party_settings: {  }
+  field_oe_social_media_links:
+    weight: 3
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+    type: typed_link
+    region: content
+  field_oe_social_media_see_more:
+    weight: 4
+    settings:
+      placeholder_url: ''
+      placeholder_title: ''
+    third_party_settings: {  }
+    type: link_default
+    region: content
+  field_oe_social_media_variant:
+    weight: 0
+    settings: {  }
+    third_party_settings: {  }
+    type: options_select
+    region: content
+  field_oe_title:
+    weight: 2
+    settings:
+      size: 60
+      placeholder: ''
+    third_party_settings: {  }
+    type: string_textfield
+    region: content
+hidden:
+  created: true
+  status: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_accordion_item.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_accordion_item.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8c3a67f6a8eb54e91907ed324a6cc13b39d354ab
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_accordion_item.default.yml
@@ -0,0 +1,32 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_accordion_item.field_oe_icon
+    - field.field.paragraph.oe_accordion_item.field_oe_text
+    - field.field.paragraph.oe_accordion_item.field_oe_text_long
+    - paragraphs.paragraphs_type.oe_accordion_item
+  module:
+    - text
+id: paragraph.oe_accordion_item.default
+targetEntityType: paragraph
+bundle: oe_accordion_item
+mode: default
+content:
+  field_oe_text:
+    weight: 0
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+  field_oe_text_long:
+    weight: 1
+    label: above
+    settings: {  }
+    third_party_settings: {  }
+    type: text_default
+    region: content
+hidden:
+  field_oe_icon: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_description_list.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_description_list.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b303a9e948f2afefed72a181681a3b630806259f
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_description_list.default.yml
@@ -0,0 +1,32 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_description_list.oe_w_orientation
+    - field.field.paragraph.oe_description_list.field_oe_description_list_items
+    - field.field.paragraph.oe_description_list.field_oe_title
+    - paragraphs.paragraphs_type.oe_description_list
+  module:
+    - description_list_field
+id: paragraph.oe_description_list.default
+targetEntityType: paragraph
+bundle: oe_description_list
+mode: default
+content:
+  field_oe_description_list_items:
+    weight: 1
+    label: hidden
+    settings: {  }
+    third_party_settings: {  }
+    type: description_list_formatter
+    region: content
+  field_oe_title:
+    weight: 0
+    label: hidden
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+hidden:
+  oe_w_orientation: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_facts_figures.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_facts_figures.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6b3d6961e433fcc76b6cdd48466e6fb9e1f10a63
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_facts_figures.default.yml
@@ -0,0 +1,48 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_facts_figures.field_oe_link
+    - field.field.paragraph.oe_facts_figures.field_oe_paragraphs
+    - field.field.paragraph.oe_facts_figures.field_oe_title
+    - field.field.paragraph.oe_facts_figures.oe_w_n_columns
+    - paragraphs.paragraphs_type.oe_facts_figures
+  module:
+    - entity_reference_revisions
+    - link
+id: paragraph.oe_facts_figures.default
+targetEntityType: paragraph
+bundle: oe_facts_figures
+mode: default
+content:
+  field_oe_link:
+    weight: 2
+    label: above
+    settings:
+      trim_length: 80
+      url_only: false
+      url_plain: false
+      rel: ''
+      target: ''
+    third_party_settings: {  }
+    type: link
+    region: content
+  field_oe_paragraphs:
+    weight: 1
+    label: above
+    settings:
+      view_mode: default
+      link: ''
+    third_party_settings: {  }
+    type: entity_reference_revisions_entity_view
+    region: content
+  field_oe_title:
+    weight: 0
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+hidden:
+  oe_w_n_columns: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_links_block.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_links_block.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0d927d07494e95fdfc6b4b8c7acb9cfe479221fc
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_links_block.default.yml
@@ -0,0 +1,39 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_links_block.field_oe_links
+    - field.field.paragraph.oe_links_block.field_oe_links_block_background
+    - field.field.paragraph.oe_links_block.field_oe_links_block_orientation
+    - field.field.paragraph.oe_links_block.field_oe_text
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - link
+id: paragraph.oe_links_block.default
+targetEntityType: paragraph
+bundle: oe_links_block
+mode: default
+content:
+  field_oe_links:
+    weight: 1
+    label: above
+    settings:
+      trim_length: 80
+      url_only: false
+      url_plain: false
+      rel: ''
+      target: ''
+    third_party_settings: {  }
+    type: link
+    region: content
+  field_oe_text:
+    weight: 0
+    label: above
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+hidden:
+  field_oe_links_block_background: true
+  field_oe_links_block_orientation: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_social_media_follow.default.yml b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_social_media_follow.default.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1177db68e7a9422cc1724e9af370f54eb2257ba7
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/core.entity_view_display.paragraph.oe_social_media_follow.default.yml
@@ -0,0 +1,53 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.field.paragraph.oe_social_media_follow.oe_w_links_block_background
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_links
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_see_more
+    - field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant
+    - field.field.paragraph.oe_social_media_follow.field_oe_title
+    - paragraphs.paragraphs_type.oe_social_media_follow
+  module:
+    - link
+    - typed_link
+id: paragraph.oe_social_media_follow.default
+targetEntityType: paragraph
+bundle: oe_social_media_follow
+mode: default
+content:
+  field_oe_social_media_links:
+    weight: 1
+    label: hidden
+    settings:
+      trim_length: 80
+      url_only: false
+      url_plain: false
+      rel: ''
+      target: ''
+    third_party_settings: {  }
+    type: typed_link
+    region: content
+  field_oe_social_media_see_more:
+    weight: 2
+    label: hidden
+    settings:
+      trim_length: 80
+      url_only: false
+      url_plain: false
+      rel: ''
+      target: ''
+    third_party_settings: {  }
+    type: link
+    region: content
+  field_oe_title:
+    weight: 0
+    label: hidden
+    settings:
+      link_to_entity: false
+    third_party_settings: {  }
+    type: string
+    region: content
+hidden:
+  oe_w_links_block_background: true
+  field_oe_social_media_variant: true
diff --git a/modules/oe_whitelabel_paragraphs/config/overrides/field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant.yml b/modules/oe_whitelabel_paragraphs/config/overrides/field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant.yml
new file mode 100755
index 0000000000000000000000000000000000000000..ecf09e79bba7735bac6ef639e4ee10889593bcb7
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/config/overrides/field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.field_oe_social_media_variant
+    - paragraphs.paragraphs_type.oe_social_media_follow
+  module:
+    - options
+id: paragraph.oe_social_media_follow.field_oe_social_media_variant
+field_name: field_oe_social_media_variant
+entity_type: paragraph
+bundle: oe_social_media_follow
+label: Orientation
+description: ''
+required: true
+translatable: false
+default_value:
+  -
+    value: horizontal
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.info.yml b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8495f5f43041949235949ca7e5e72a206bb6d526
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.info.yml
@@ -0,0 +1,23 @@
+name: OpenEuropa Whitelabel Paragraphs
+type: module
+description: Companion module to add support and customisations for oe_paragraphs.
+package: OpenEuropa Whitelabel Theme
+core_version_requirement: ^9.2
+dependencies:
+  - drupal:description_list_field
+  - oe_content:oe_content_timeline_field
+  - oe_paragraphs:oe_paragraphs
+  - oe_paragraphs:oe_paragraphs_description_list
+  - oe_paragraphs:oe_paragraphs_timeline
+  - oe_whitelabel:oe_whitelabel_helper
+config_devel:
+  install:
+    - field.field.paragraph.oe_description_list.oe_w_orientation
+    - field.field.paragraph.oe_facts_figures.oe_w_n_columns
+    - field.field.paragraph.oe_links_block.oe_w_links_block_background
+    - field.field.paragraph.oe_links_block.oe_w_links_block_orientation
+    - field.field.paragraph.oe_social_media_follow.oe_w_links_block_background
+    - field.storage.paragraph.oe_w_links_block_background
+    - field.storage.paragraph.oe_w_links_block_orientation
+    - field.storage.paragraph.oe_w_n_columns
+    - field.storage.paragraph.oe_w_orientation
diff --git a/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.install b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.install
new file mode 100644
index 0000000000000000000000000000000000000000..5d300a8f1308ab16b95b87546c3256d5459396dc
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.install
@@ -0,0 +1,193 @@
+<?php
+
+/**
+ * @file
+ * Install and update functions for the OE Whitelabel Paragraphs module.
+ */
+
+declare(strict_types = 1);
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\oe_bootstrap_theme\ConfigImporter;
+
+/**
+ * Implements hook_install().
+ *
+ * Customizes paragraphs fields and display configuration.
+ *
+ * If oe_bootstrap_theme_paragraphs was installed in the past, this will also
+ * migrate field data and clean up fields that have been renamed.
+ */
+function oe_whitelabel_paragraphs_install(bool $is_syncing): void {
+  // Find legacy fields from oe_bootstrap_theme_paragraphs.
+  // This needs to happen at the start, to allow for early abort.
+  $field_names_by_bundle = _oe_whitelabel_paragraphs_install_get_legacy_fields_map();
+
+  if ($is_syncing) {
+    // The module is being installed as part of a config import.
+    if ($field_names_by_bundle) {
+      // There is data to be migrated. This should not happen as a side effect
+      // of config-import. Instead, the installation should be enacted from an
+      // update hook.
+      throw new \Exception('This module should be installed through an update hook, not through config-import, if there is still leftover data from oe_bootstrap_theme_paragraphs to migrate.');
+    }
+    // No data needs to be migrated, but still, no configuration should be
+    // imported in hook_install() during config-import.
+    return;
+  }
+
+  // The module is being installed explicitly, e.g. via a hook_update_N().
+  // Configuration needs to be imported explicitly.
+  _oe_whitelabel_paragraphs_install_config();
+
+  if (!$field_names_by_bundle) {
+    // No fields to migrate and clean up - finished.
+    return;
+  }
+
+  _oe_whitelabel_paragraphs_install_migrate_field_data($field_names_by_bundle);
+  _oe_whitelabel_paragraphs_install_drop_legacy_fields($field_names_by_bundle);
+}
+
+/**
+ * Imports configuration on module install.
+ */
+function _oe_whitelabel_paragraphs_install_config(): void {
+  $configs = [
+    'core.entity_form_display.paragraph.oe_accordion_item.default',
+    'core.entity_form_display.paragraph.oe_description_list.default',
+    'core.entity_form_display.paragraph.oe_facts_figures.default',
+    'core.entity_form_display.paragraph.oe_links_block.default',
+    'core.entity_form_display.paragraph.oe_list_item.default',
+    'core.entity_form_display.paragraph.oe_list_item_block.default',
+    'core.entity_form_display.paragraph.oe_list_item_block.highlight',
+    'core.entity_form_display.paragraph.oe_social_media_follow.default',
+    'core.entity_view_display.paragraph.oe_accordion_item.default',
+    'core.entity_view_display.paragraph.oe_description_list.default',
+    'core.entity_view_display.paragraph.oe_facts_figures.default',
+    'core.entity_view_display.paragraph.oe_links_block.default',
+    'core.entity_view_display.paragraph.oe_social_media_follow.default',
+    'field.field.paragraph.oe_social_media_follow.field_oe_social_media_variant',
+  ];
+
+  ConfigImporter::importMultiple('oe_whitelabel_paragraphs', '/config/overrides/', $configs);
+}
+
+/**
+ * Gets a map of legacy fields to be migrated on install.
+ *
+ * @return string[][]
+ *   Legacy field names, indexed by paragraph type and destination field name.
+ *   Only contains entries where both the legacy field name and the destination
+ *   field name do exist.
+ *   Empty, if oe_bootstrap_theme_paragraphs was not installed in the past.
+ */
+function _oe_whitelabel_paragraphs_install_get_legacy_fields_map(): array {
+  /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+  $fields_map = $entity_field_manager->getFieldMap()['paragraph'] ?? [];
+
+  $field_names_by_bundle = [
+    'oe_description_list' => [
+      'oe_w_orientation' => 'oe_bt_orientation',
+    ],
+    'oe_facts_figures' => [
+      'oe_w_n_columns' => 'oe_bt_n_columns',
+    ],
+    'oe_links_block' => [
+      'oe_w_links_block_background' => 'oe_bt_links_block_background',
+      'oe_w_links_block_orientation' => 'oe_bt_links_block_orientation',
+    ],
+    'oe_social_media_follow' => [
+      'oe_w_links_block_background' => 'oe_bt_links_block_background',
+    ],
+  ];
+
+  foreach ($field_names_by_bundle as $bundle => $field_names) {
+    foreach ($field_names as $dest_field_name => $source_field_name) {
+      if (!isset($fields_map[$source_field_name]['bundles'][$bundle])) {
+        // The legacy field does not exist.
+        // Perhaps the field or the paragraph type were removed manually.
+        unset($field_names_by_bundle[$bundle][$dest_field_name]);
+        continue;
+      }
+      if (!isset($fields_map[$dest_field_name]['bundles'][$bundle])) {
+        // A destination field is missing, that should have been created
+        // earlier. This could happen if a paragraph type was removed manually,
+        // but in that case the install should have already failed earlier.
+        // Either way, this case is not supported.
+        throw new \RuntimeException("Destination field 'paragraph.$bundle.$dest_field_name' was not properly created.");
+      }
+    }
+  }
+
+  return array_filter($field_names_by_bundle);
+}
+
+/**
+ * Migrates field data from the old oe_bootstrap_theme_paragraphs module.
+ *
+ * This should happen through a batch process, e.g. via $sandbox in a
+ * hook_update_N(). Unfortunately, hook_install() does not support batch
+ * processes.
+ *
+ * @param string[][] $field_names_by_bundle
+ *   Legacy field names, indexed by paragraph type and destination field name.
+ */
+function _oe_whitelabel_paragraphs_install_migrate_field_data(array $field_names_by_bundle): void {
+  $paragraphs_storage = \Drupal::entityTypeManager()->getStorage('paragraph');
+
+  // Load all the paragraph ids.
+  $query = $paragraphs_storage->getQuery();
+  $query->allRevisions();
+  $query->condition('type', array_keys($field_names_by_bundle), 'IN');
+  $paragraph_ids = $query->execute();
+
+  foreach ($paragraph_ids as $revision_id => $paragraph_id) {
+    // Revision can't be NULL.
+    /** @var \Drupal\paragraphs\ParagraphInterface $paragraph_revision */
+    $paragraph_revision = $paragraphs_storage->loadRevision($revision_id);
+    $field_names_map = $field_names_by_bundle[$paragraph_revision->bundle()];
+    $modified = FALSE;
+    foreach ($field_names_map as $dest_field_name => $source_field_name) {
+      if ($paragraph_revision->get($source_field_name)->isEmpty()) {
+        // Source field has no data.
+        continue;
+      }
+      if (!$paragraph_revision->get($dest_field_name)->isEmpty()) {
+        // Destination already has data.
+        continue;
+      }
+      // Copy the field value.
+      // For these simple field types, magic __set() does the job.
+      $paragraph_revision->$dest_field_name = $paragraph_revision->$source_field_name;
+      // Do not unset the old field, because it might be required.
+      // Remember that the revision needs saving.
+      $modified = TRUE;
+    }
+    if (!$modified) {
+      // No saving is needed.
+      continue;
+    }
+    $paragraph_revision->setNewRevision(FALSE);
+    $paragraph_revision->save();
+  }
+}
+
+/**
+ * Removes legacy field instances from oe_bootstrap_theme_paragraphs module.
+ *
+ * @param string[][] $field_names_by_bundle
+ *   Legacy field names, indexed by paragraph type and destination field name.
+ */
+function _oe_whitelabel_paragraphs_install_drop_legacy_fields(array $field_names_by_bundle): void {
+  foreach ($field_names_by_bundle as $bundle => $legacy_field_names) {
+    foreach ($legacy_field_names as $legacy_field_name) {
+      $field_config = FieldConfig::loadByName('paragraph', $bundle, $legacy_field_name);
+      if ($field_config === NULL) {
+        throw new \RuntimeException("Legacy field 'paragraph.$bundle.$legacy_field_name' not found.");
+      }
+      $field_config->delete();
+    }
+  }
+}
diff --git a/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.module b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.module
new file mode 100644
index 0000000000000000000000000000000000000000..e8a17b933c8fedf45fa7806932095cfa9a5f68f2
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.module
@@ -0,0 +1,538 @@
+<?php
+
+/**
+ * @file
+ * OE Whitelabel Paragraphs module.
+ *
+ * Preprocess hooks are implemented on behalf of the oe_whitelabel theme.
+ * This prevents hooks from running if oe_whitelabel is not the active theme.
+ */
+
+declare(strict_types = 1);
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
+use Drupal\media\Entity\Media;
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaSourceInterface;
+use Drupal\media\Plugin\media\Source\Image;
+use Drupal\media\Plugin\media\Source\OEmbed;
+use Drupal\media_avportal\Plugin\media\Source\MediaAvPortalPhotoSource;
+use Drupal\media_avportal\Plugin\media\Source\MediaAvPortalSourceInterface;
+use Drupal\media_avportal\Plugin\media\Source\MediaAvPortalVideoSource;
+use Drupal\oe_bootstrap_theme\ValueObject\ImageValueObject;
+use Drupal\oe_media_iframe\Plugin\media\Source\Iframe;
+use Drupal\paragraphs\Entity\Paragraph;
+
+/**
+ * Implements hook_theme_suggestions_HOOK_alter().
+ *
+ * Adds a bare, markup-free template suggestion to all paragraph fields.
+ */
+function oe_whitelabel_paragraphs_theme_suggestions_field_alter(array &$suggestions, array $variables): void {
+  $element = $variables['element'];
+
+  // Do not output field labels and wrapping markup for paragraph fields.
+  if (isset($element['#entity_type']) && $element['#entity_type'] === 'paragraph') {
+    // Prepend the new suggestion to the list. This will put it right after the
+    // default field template. By doing this we allow to override single
+    // fields, while keeping all the rest markup-free.
+    array_unshift($suggestions, 'field__bare');
+  }
+}
+
+/**
+ * Implements hook_preprocess_paragraph().
+ */
+function oe_whitelabel_preprocess_paragraph__oe_links_block(array &$variables): void {
+  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+  $variables['orientation'] = $paragraph->get('oe_w_links_block_orientation')->value;
+  $variables['background'] = $paragraph->get('oe_w_links_block_background')->value;
+  if (!$paragraph->get('field_oe_text')->isEmpty()) {
+    $variables['title'] = $paragraph->get('field_oe_text')->value;
+  }
+
+  foreach (Element::children($variables['content']['field_oe_links']) as $index) {
+    $variables['links'][] = [
+      'label' => $variables['content']['field_oe_links'][$index]['#title'],
+      'path' => $variables['content']['field_oe_links'][$index]['#url']->toString(),
+    ];
+  }
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for oe_social_media_follow paragraph.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_social_media_follow(array &$variables): void {
+  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+  $variables['orientation'] = $paragraph->get('field_oe_social_media_variant')->value;
+  $variables['background'] = $paragraph->get('oe_w_links_block_background')->value;
+  if (!$paragraph->get('field_oe_title')->isEmpty()) {
+    $variables['title'] = $paragraph->get('field_oe_title')->value;
+  }
+  $links = $paragraph->get('field_oe_social_media_links')->getValue();
+  $variables['links'] = [];
+  foreach ($links as $key => $link) {
+    $variables['links'][$key]['icon_position'] = 'before';
+    $variables['links'][$key]['icon']['path'] = $variables['bcl_icon_path'];
+    $variables['links'][$key]['icon']['name'] = $link['link_type'];
+    $variables['links'][$key]['label'] = $link['title'];
+    $variables['links'][$key]['path'] = Url::fromUri($link['uri'])->toString();
+  }
+  if (!$paragraph->get('field_oe_social_media_see_more')->isEmpty()) {
+    $other_link = $paragraph->get('field_oe_social_media_see_more')
+      ->first()
+      ->getValue();
+    $variables['links'][] = [
+      'label' => $other_link['title'],
+      'path' => Url::fromUri($other_link['uri'])->toString(),
+    ];
+  }
+}
+
+/**
+ * Implements hook_preprocess_paragraph__oe_accordion().
+ */
+function oe_whitelabel_preprocess_paragraph__oe_accordion(array &$variables): void {
+  // Massage data to be compliant with OE Bootstrap Theme accordion pattern
+  // data structure.
+  $builder = \Drupal::entityTypeManager()->getViewBuilder('paragraph');
+  $variables['items'] = [];
+
+  /** @var \Drupal\entity_reference_revisions\Plugin\Field\FieldType\EntityReferenceRevisionsItem $field_item */
+  foreach ($variables['paragraph']->get('field_oe_paragraphs') as $field_item) {
+    $paragraph = \Drupal::service('entity.repository')->getTranslationFromContext($field_item->entity);
+    $variables['items'][] = [
+      'title' => $builder->viewField($paragraph->get('field_oe_text')),
+      'content' => $builder->viewField($paragraph->get('field_oe_text_long')),
+    ];
+  }
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for paragraph--oe-text-feature-media.html.twig.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_text_feature_media(array &$variables): void {
+  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+
+  // Bail out if there is no media present.
+  if ($paragraph->get('field_oe_media')->isEmpty()) {
+    return;
+  }
+
+  /** @var \Drupal\media\Entity\Media $media */
+  $media = $paragraph->get('field_oe_media')->entity;
+  if (!$media instanceof MediaInterface) {
+    // The media entity is not available anymore, bail out.
+    return;
+  }
+
+  // Retrieve the correct media translation.
+  /** @var \Drupal\media\Entity\Media $media */
+  $media = \Drupal::service('entity.repository')->getTranslationFromContext($media, $paragraph->language()->getId());
+
+  // Caches are handled by the formatter usually. Since we are not rendering
+  // the original render arrays, we need to propagate our caches to the
+  // paragraph template.
+  $cacheability = CacheableMetadata::createFromRenderArray($variables);
+  $cacheability->addCacheableDependency($media);
+
+  // Run access checks on the media entity.
+  $access = $media->access('view', $variables['user'], TRUE);
+  $cacheability->addCacheableDependency($access);
+  if (!$access->isAllowed()) {
+    $cacheability->applyTo($variables);
+    return;
+  }
+
+  // Get the media source.
+  $source = $media->getSource();
+
+  $is_image = $source instanceof MediaAvPortalPhotoSource || $source instanceof Image;
+  $is_video = $source instanceof MediaAvPortalVideoSource || $source instanceof OEmbed || $source instanceof Iframe;
+
+  // If it's not an image and not a video, bail out.
+  if (!$is_image && !$is_video) {
+    $cacheability->applyTo($variables);
+    return;
+  }
+
+  $variant = $paragraph->get('oe_paragraphs_variant')->value ?? 'default';
+  $variables['text_position'] = str_replace([
+    '_featured',
+    '_simple',
+  ], '', $variant);
+
+  if ($is_image) {
+    $thumbnail = $media->get('thumbnail')->first();
+    $variables['image'] = ImageValueObject::fromStyledImageItem($thumbnail, 'oe_bootstrap_theme_medium_no_crop');
+  }
+  elseif ($is_video) {
+    _oe_whitelabel_featured_media_set_embedded_media($variables, $media, $cacheability, $source);
+  }
+
+  $cacheability->applyTo($variables);
+
+  if (empty($paragraph->get('field_oe_link')->first())) {
+    return;
+  }
+
+  /** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $link_item */
+  $link_item = $paragraph->get('field_oe_link')->first();
+  $variables['link'] = [
+    'path' => $link_item->getUrl()->toString(),
+    'label' => $link_item->get('title')->getValue(),
+  ];
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for paragraph--oe-list-item-block.html.twig.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_list_item_block(array &$variables): void {
+  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+
+  // @todo Use ->isEmpty() as in other preprocess functions.
+  //   In the OpenEuropa team it was decided that ->isEmpty() calls should be
+  //   the preferred way to deal with empty field values.
+  //   This function instead relies on ->value or ->first() returning NULL for
+  //   empty fields, which the team is not fully confident about, and which does
+  //   not follow the team convention.
+  //   It was agreed to keep it like this for now in this function, but refactor
+  //   it in the future.
+  //   See also https://www.drupal.org/project/drupal/issues/3268137.
+  $variables['variant'] = $paragraph->get('oe_paragraphs_variant')->value;
+  $variables['title'] = $paragraph->get('field_oe_title')->value;
+
+  $layout_name = $paragraph->get('field_oe_list_item_block_layout')->value;
+  $variables['columns'] = ['two_columns' => '2', 'three_columns' => '3'][$layout_name] ?? '1';
+
+  $variables['items'] = [];
+  foreach ($variables['paragraph']->get('field_oe_paragraphs') as $card_paragraph_item) {
+    /** @var \Drupal\paragraphs\ParagraphInterface $card_paragraph */
+    $card_paragraph = $card_paragraph_item->entity;
+
+    /** @var \Drupal\file\Plugin\Field\FieldType\FileFieldItemList $card_image_items */
+    $card_image_items = $card_paragraph->get('field_oe_image');
+    /** @var \Drupal\file\FileInterface|null $card_image_file */
+    $card_image_file = $card_image_items->entity;
+    $card_image = $card_image_file ? [
+      'path' => file_url_transform_relative(file_create_url($card_image_file->getFileUri())),
+      'alt' => $card_image_items->alt,
+    ] : [];
+
+    // Prepare the metas if available.
+    $card_badges = [];
+    foreach ($card_paragraph->get('field_oe_meta') as $meta_item) {
+      $card_badges[] = $meta_item->value;
+    }
+
+    $card_title = $card_paragraph->get('field_oe_title')->value;
+    /** @var \Drupal\link\LinkItemInterface|null $card_link_item */
+    $card_link_item = $card_paragraph->get('field_oe_link')->first();
+    $variables['items'][] = [
+      'title' => $card_title,
+      'url' => $card_link_item ? $card_link_item->getUrl() : '',
+      'text' => $card_paragraph->get('field_oe_text_long')->value,
+      'image' => $card_image,
+      'badges' => $card_badges,
+    ];
+  }
+
+  // Prepare the button variables if a link has been specified.
+  /** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $link_item */
+  $link_item = $paragraph->get('field_oe_link')->first();
+  $variables['link'] = $link_item ? [
+    'path' => $link_item->getUrl()->toString(),
+    'label' => $link_item->title,
+    'icon' => [
+      'path' => $variables['bcl_icon_path'],
+      'name' => 'chevron-right',
+    ],
+  ] : NULL;
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for oe_banner paragraph.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_banner(array &$variables): void {
+  /** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+  $variables['title'] = $paragraph->get('field_oe_title')->value;
+  $variables['description'] = $paragraph->get('field_oe_text')->value;
+  $variables['full_width'] = (bool) $paragraph->get('field_oe_banner_full_width')->value;
+  _oe_whitelabel_set_banner_link($paragraph, $variables);
+
+  // The alignment field value contains the information regarding the pattern
+  // type and centering.
+  $alignment = $paragraph->get('field_oe_banner_type')->value;
+  [$banner_type, $banner_alignment] = explode('_', $alignment);
+  // The beginning of the string determines the pattern.
+  $variables['pattern'] = 'banner_' . $banner_type;
+  // The end of the string determines the position.
+  $variables['alignment'] = $banner_alignment;
+
+  $variant = $paragraph->get('oe_paragraphs_variant')->value ?? 'default';
+  $variables['variant'] = str_replace('oe_banner_', '', $variant);
+
+  if ($variables['variant'] === 'default' || $variables['variant'] === 'primary') {
+    return;
+  }
+
+  // Bail out if there is no media present.
+  if ($paragraph->get('field_oe_media')->isEmpty()) {
+    return;
+  }
+  $cacheability = CacheableMetadata::createFromRenderArray($variables);
+
+  /** @var \Drupal\media\Entity\Media $media */
+  $media = $paragraph->get('field_oe_media')->entity;
+  if (!$media instanceof MediaInterface) {
+    // The media entity is not available anymore, bail out.
+    return;
+  }
+
+  // Retrieve the correct translation to display.
+  $media = \Drupal::service('entity.repository')->getTranslationFromContext($media, $paragraph->language()->getId());
+
+  // Caches are handled by the formatter usually. Since we are not rendering
+  // the original render arrays, we need to propagate our caches to the
+  // paragraph template.
+  $cacheability->addCacheableDependency($media);
+
+  // Run access checks on the media entity.
+  $access = $media->access('view', $variables['user'], TRUE);
+  $cacheability->addCacheableDependency($access);
+  if (!$access->isAllowed()) {
+    $cacheability->applyTo($variables);
+    return;
+  }
+
+  $source = $media->getSource();
+  // We only support images and AV Portal photos for now.
+  if (!$source instanceof MediaAvPortalSourceInterface && !$source instanceof Image) {
+    $cacheability->applyTo($variables);
+    return;
+  }
+
+  $uri = _oe_whitelabel_get_media_uri($source, $media, $cacheability);
+
+  // The uri might be empty if the source is of type Image and the file entity
+  // was deleted.
+  if (empty($uri)) {
+    $cacheability->applyTo($variables);
+    return;
+  }
+
+  $variables['image'] = ImageValueObject::fromArray([
+    'src' => file_create_url($uri),
+    'alt' => $source->getMetadata($media, 'thumbnail_alt_value') ?? $media->label(),
+    'name' => $media->getName(),
+  ]);
+  $cacheability->applyTo($variables);
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for timeline paragraph.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_timeline(array &$variables): void {
+  $paragraph = $variables['paragraph'];
+  if (!$paragraph->get('field_oe_title')->isEmpty()) {
+    $variables['heading'] = $paragraph->get('field_oe_title')->value;
+  }
+
+  if (!isset($variables['content']['field_oe_timeline']['#items'])) {
+    return;
+  }
+  // Adapting body to content as defined in pattern.
+  foreach ($variables['content']['field_oe_timeline']['#items'] as &$timeline_item) {
+    $timeline_item['content'] = $timeline_item['body'];
+    unset($timeline_item['body']);
+    $variables['content']['items'][] = $timeline_item;
+  }
+  $variables['hide_from'] = $paragraph->get('field_oe_timeline_expand')->value;
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for paragraph--oe-content-row--variant-inpage-navigation.html.twig.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_content_row__variant_inpage_navigation(array &$variables): void {
+  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+
+  if ($paragraph->get('field_oe_paragraphs')->isEmpty()) {
+    return;
+  }
+
+  $variables['attributes']['id'] = Html::getUniqueId('bcl-inpage-navigation-pid-' . $paragraph->id());
+
+  $variables['title'] = t('Page contents');
+  if (!$paragraph->get('field_oe_title')->isEmpty()) {
+    $variables['title'] = $paragraph->get('field_oe_title')->value;
+  }
+
+  $field_render = &$variables['content']['field_oe_paragraphs'];
+  $links = [];
+  foreach ($paragraph->get('field_oe_paragraphs')->referencedEntities() as $delta => $sub_paragraph) {
+    /** @var \Drupal\paragraphs\Entity\Paragraph $sub_paragraph */
+    if (!$sub_paragraph->hasField('field_oe_title') || $sub_paragraph->get('field_oe_title')->isEmpty()) {
+      continue;
+    }
+
+    $unique_id = Html::getUniqueId('bcl-inpage-item-' . $sub_paragraph->id());
+    $field_render[$delta]['#theme_wrappers']['container'] = [
+      '#attributes' => ['id' => $unique_id],
+    ];
+
+    $sub_paragraph = \Drupal::service('entity.repository')
+      ->getTranslationFromContext($sub_paragraph, $paragraph->language()->getId());
+
+    $links[] = [
+      'path' => '#' . $unique_id,
+      'label' => $sub_paragraph->get('field_oe_title')->first()->value,
+    ];
+  }
+
+  $variables['links'] = $links;
+}
+
+/**
+ * Implements hook_preprocess_paragraph() for oe_description-list paragraph.
+ */
+function oe_whitelabel_preprocess_paragraph__oe_description_list(array &$variables): void {
+  /** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
+  $paragraph = $variables['paragraph'];
+  $variables['title'] = $paragraph->get('field_oe_title')->value ?? '';
+  $variables['orientation'] = $paragraph->get('oe_w_orientation')->value;
+
+  foreach ($paragraph->get('field_oe_description_list_items') as $item) {
+    $variables['items'][] = [
+      'term' => $item->term,
+      'definition' => $item->description,
+    ];
+  }
+}
+
+/**
+ * Implements hook_preprocess_paragraph().
+ */
+function oe_whitelabel_preprocess_paragraph__oe_facts_figures(array &$variables): void {
+  /** @var \Drupal\paragraphs\ParagraphInterface $paragraph */
+  $paragraph = $variables['paragraph'];
+  if (!$paragraph->get('field_oe_title')->isEmpty()) {
+    $variables['title'] = $paragraph->get('field_oe_title')->value;
+  }
+
+  if (!$paragraph->get('field_oe_link')->isEmpty()) {
+    $link_item = $paragraph->get('field_oe_link')->first();
+    $variables['link_more']['path'] = $link_item->getUrl()->toString();
+    $variables['link_more']['label'] = $link_item->get('title')->getValue();
+  }
+  $variables['items'] = [];
+
+  /** @var \Drupal\paragraphs\Entity\Paragraph $sub_paragraph */
+  foreach ($paragraph->get('field_oe_paragraphs')->referencedEntities() as $sub_paragraph) {
+    // Get the paragraph translation.
+    $sub_paragraph = \Drupal::service('entity.repository')
+      ->getTranslationFromContext($sub_paragraph, $paragraph->language()->getId());
+    $description = '';
+    if (!$sub_paragraph->get('field_oe_plain_text_long')->isEmpty()) {
+      $description = $sub_paragraph->get('field_oe_plain_text_long')->value;
+    }
+    $variables['items'][] = [
+      'icon' => $sub_paragraph->get('field_oe_icon')->value,
+      'title' => $sub_paragraph->get('field_oe_title')->value,
+      'subtitle' => $sub_paragraph->get('field_oe_subtitle')->value,
+      'description' => $description,
+    ];
+  }
+
+  if (!$paragraph->get('oe_w_n_columns')->isEmpty()) {
+    $variables['columns'] = $paragraph->get('oe_w_n_columns')->value;
+  }
+}
+
+/**
+ * Sets link variable for banner paragraph.
+ *
+ * @param \Drupal\paragraphs\Entity\Paragraph $paragraph
+ *   The paragraph.
+ * @param array $variables
+ *   The render array.
+ */
+function _oe_whitelabel_set_banner_link(Paragraph $paragraph, array &$variables): void {
+  if ($paragraph->get('field_oe_link')->isEmpty()) {
+    return;
+  }
+
+  $link = $paragraph->get('field_oe_link')->first();
+  $variables['url'] = $link->getUrl()->toString();
+  $variables['label'] = $link->get('title')->getValue();
+}
+
+/**
+ * Gets the uri from a media object.
+ *
+ * @param \Drupal\media\MediaSourceInterface $source
+ *   The media source.
+ * @param \Drupal\media\Entity\Media $media
+ *   The media object.
+ * @param \Drupal\Core\Cache\CacheableMetadata $cacheability
+ *   The cacheability object.
+ *
+ * @return string
+ *   The uri string.
+ */
+function _oe_whitelabel_get_media_uri(MediaSourceInterface $source, Media $media, CacheableMetadata $cacheability): string {
+  $field_name = $source->getConfiguration()['source_field'];
+
+  if ($source instanceof Image && ($file_entity = $media->get($field_name)->entity)) {
+    $cacheability->addCacheableDependency($file_entity);
+    return $file_entity->getFileUri();
+  }
+
+  if ($source instanceof MediaAvPortalSourceInterface) {
+    $resource_ref = $media->get($field_name)->value;
+    return 'avportal://' . $resource_ref . '.jpg';
+  }
+
+  return '';
+}
+
+/**
+ * Prepares embedded media variables for "text with featured media" paragraph.
+ *
+ * @param array $variables
+ *   The render array.
+ * @param \Drupal\media\MediaInterface $media
+ *   Media object.
+ * @param \Drupal\Core\Cache\CacheableMetadata $cacheability
+ *   CacheableMetadata object.
+ * @param \Drupal\media\MediaSourceInterface $source
+ *   Media source.
+ */
+function _oe_whitelabel_featured_media_set_embedded_media(array &$variables, MediaInterface $media, CacheableMetadata $cacheability, MediaSourceInterface $source): void {
+  // Default video aspect ratio is set to 16x9.
+  $variables['ratio'] = '16x9';
+
+  // Load information about the media and the display.
+  $media_type = \Drupal::entityTypeManager()->getStorage('media_type')->load($media->bundle());
+  $cacheability->addCacheableDependency($media_type);
+  $source_field = $source->getSourceFieldDefinition($media_type);
+  $display = EntityViewDisplay::collectRenderDisplay($media, 'default');
+  $cacheability->addCacheableDependency($display);
+  $display_options = $display->getComponent($source_field->getName());
+
+  $variables['embedded_media'] = $media->{$source_field->getName()}->view($display_options);
+
+  if ($media->bundle() === 'video_iframe') {
+    $ratio = $media->get('oe_media_iframe_ratio')->value;
+    $variables['ratio'] = str_replace('_', 'x', $ratio);
+  }
+}
diff --git a/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.services.yml b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.services.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5dfebd8df61f745e482f6c0940c9b5c145573723
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/oe_whitelabel_paragraphs.services.yml
@@ -0,0 +1,5 @@
+services:
+  oe_whitelabel_paragraphs.icon_options_subscriber:
+    class: 'Drupal\oe_whitelabel_paragraphs\EventSubscriber\IconOptionsSubscriber'
+    tags:
+      - { name: 'event_subscriber' }
diff --git a/modules/oe_whitelabel_paragraphs/src/EventSubscriber/IconOptionsSubscriber.php b/modules/oe_whitelabel_paragraphs/src/EventSubscriber/IconOptionsSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..38785ea5ba0d0797601e9d7545f49afe6ff8bf6b
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/src/EventSubscriber/IconOptionsSubscriber.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\oe_whitelabel_paragraphs\EventSubscriber;
+
+use Drupal\oe_paragraphs\Event\IconOptionsEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Provides options for the icon field.
+ *
+ * @see \Drupal\oe_paragraphs\EventSubscriber\OptionsSubscriber
+ * @see _oe_paragraphs_allowed_values_icons()
+ */
+class IconOptionsSubscriber implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    return [
+      IconOptionsEvent::class => ['getIconOptions', -1],
+    ];
+  }
+
+  /**
+   * Gets the icon options.
+   *
+   * @param \Drupal\oe_paragraphs\Event\IconOptionsEvent $event
+   *   Allowed format event object.
+   */
+  public function getIconOptions(IconOptionsEvent $event): void {
+    $event->setIconOptions([
+      'arrow-down' => 'Arrow down',
+      'box-arrow-up' => 'External',
+      'arrow-up' => 'Arrow up',
+      'book' => 'Book',
+      'camera' => 'Camera',
+      'check' => 'Check',
+      'download' => 'Download',
+      'currency-euro' => 'Euro',
+      'facebook' => 'Facebook',
+      'file' => 'File',
+      'image' => 'Image',
+      'info' => 'Info',
+      'linkedin' => 'LinkedIn',
+      'files' => 'Multiple files',
+      'rss' => 'RSS',
+      'search' => 'Search',
+      'share' => 'Share',
+      'twitter' => 'Twitter',
+      'camera-video' => 'Video',
+    ]);
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/fixtures/example_1.jpeg b/modules/oe_whitelabel_paragraphs/tests/fixtures/example_1.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..e04cde60ca8fa8d23a3668010a40f976abb78e8b
Binary files /dev/null and b/modules/oe_whitelabel_paragraphs/tests/fixtures/example_1.jpeg differ
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_description_list.oe_bt_orientation.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_description_list.oe_bt_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..73b09a472d8fca82e66e5c1a1ccda494d88fb33c
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_description_list.oe_bt_orientation.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_bt_orientation
+    - paragraphs.paragraphs_type.oe_description_list
+  module:
+    - options
+id: paragraph.oe_description_list.oe_bt_orientation
+field_name: oe_bt_orientation
+entity_type: paragraph
+bundle: oe_description_list
+label: Orientation
+description: 'Sets the orientation (vertical|horizontal) for the paragraph.'
+required: true
+translatable: false
+default_value:
+  -
+    value: horizontal
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_facts_figures.oe_bt_n_columns.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_facts_figures.oe_bt_n_columns.yml
new file mode 100644
index 0000000000000000000000000000000000000000..eec70a14e1e037db51893287df01d018fc6b868e
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_facts_figures.oe_bt_n_columns.yml
@@ -0,0 +1,24 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_bt_n_columns
+    - paragraphs.paragraphs_type.oe_facts_figures
+id: paragraph.oe_facts_figures.oe_bt_n_columns
+field_name: oe_bt_n_columns
+entity_type: paragraph
+bundle: oe_facts_figures
+label: 'Number of columns'
+description: 'Sets the number of grid columns. Minimum number is 1 column and maximum is 3.'
+required: false
+translatable: false
+default_value:
+  -
+    value: 1
+default_value_callback: ''
+settings:
+  min: 1
+  max: 3
+  prefix: ''
+  suffix: ''
+field_type: integer
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_background.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..de66c69713d5ed89c8815b1dbdb3f599a21eb2cd
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_background.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_bt_links_block_background
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - options
+id: paragraph.oe_links_block.oe_bt_links_block_background
+field_name: oe_bt_links_block_background
+entity_type: paragraph
+bundle: oe_links_block
+label: Background
+description: 'Allows to select the background color of the links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: gray
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_orientation.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..610c35d3739f035f44364e2852bebd7247e1698c
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_links_block.oe_bt_links_block_orientation.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_bt_links_block_orientation
+    - paragraphs.paragraphs_type.oe_links_block
+  module:
+    - options
+id: paragraph.oe_links_block.oe_bt_links_block_orientation
+field_name: oe_bt_links_block_orientation
+entity_type: paragraph
+bundle: oe_links_block
+label: Orientation
+description: 'Allows to select the direction of the links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: vertical
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_social_media_follow.oe_bt_links_block_background.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_social_media_follow.oe_bt_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8e167195da6f02c6d387c8ad0c0426a04a6123cb
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.field.paragraph.oe_social_media_follow.oe_bt_links_block_background.yml
@@ -0,0 +1,22 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.paragraph.oe_bt_links_block_background
+    - paragraphs.paragraphs_type.oe_social_media_follow
+  module:
+    - options
+id: paragraph.oe_social_media_follow.oe_bt_links_block_background
+field_name: oe_bt_links_block_background
+entity_type: paragraph
+bundle: oe_social_media_follow
+label: Background
+description: 'Allows to select the background color of the Social Media Links block.'
+required: false
+translatable: false
+default_value:
+  -
+    value: gray
+default_value_callback: ''
+settings: {  }
+field_type: list_string
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_background.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_background.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1a7dbec06489349b31b105c506d6256d6ca9d4f8
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_background.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_bt_links_block_background
+field_name: oe_bt_links_block_background
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: gray
+      label: Gray
+    -
+      value: transparent
+      label: Transparent
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_orientation.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d582eb8126c744b0643c987431a6cc6dfa4cbd20
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_links_block_orientation.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_bt_links_block_orientation
+field_name: oe_bt_links_block_orientation
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: horizontal
+      label: Horizontal
+    -
+      value: vertical
+      label: Vertical
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_n_columns.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_n_columns.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f2a740718db02227ad37f1ae65b8a425745e32e1
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_n_columns.yml
@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - paragraphs
+id: paragraph.oe_bt_n_columns
+field_name: oe_bt_n_columns
+entity_type: paragraph
+type: integer
+settings:
+  unsigned: false
+  size: normal
+module: core
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_orientation.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_orientation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..94f290a8e681aa0e93bef75192d167d80ea24ae5
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/config/install/field.storage.paragraph.oe_bt_orientation.yml
@@ -0,0 +1,26 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - options
+    - paragraphs
+id: paragraph.oe_bt_orientation
+field_name: oe_bt_orientation
+entity_type: paragraph
+type: list_string
+settings:
+  allowed_values:
+    -
+      value: vertical
+      label: Vertical
+    -
+      value: horizontal
+      label: Horizontal
+  allowed_values_function: ''
+module: options
+locked: false
+cardinality: 1
+translatable: true
+indexes: {  }
+persist_with_no_fields: false
+custom_storage: false
diff --git a/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/oe_whitelabel_legacy_paragraphs_test.info.yml b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/oe_whitelabel_legacy_paragraphs_test.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4cb09829c9ca4f6105cbd9ca32deef9ca7f258d5
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/modules/oe_whitelabel_legacy_paragraphs_test/oe_whitelabel_legacy_paragraphs_test.info.yml
@@ -0,0 +1,9 @@
+name: OE Whitelabel - Legacy Paragraphs Test
+type: module
+description: Provides legacy configuration as in oe_bootstrap_theme_paragraphs.
+package: Testing
+hidden: true
+dependencies:
+  - drupal:description_list_field
+  - oe_paragraphs:oe_paragraphs
+  - oe_paragraphs:oe_paragraphs_description_list
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Functional/InstallTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Functional/InstallTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6a20318f1f4f0c372696edcb19f4ec561651a8c
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Functional/InstallTest.php
@@ -0,0 +1,218 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Functional;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests installation of oe_whitelabel_paragraphs.
+ *
+ * @see oe_whitelabel_paragraphs_install()
+ */
+class InstallTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'node',
+    'oe_whitelabel_legacy_paragraphs_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Test installation with legacy fields and data present.
+   */
+  public function testInstallWithLegacyParagraphs(): void {
+    $paragraphs_data = [];
+    $paragraphs_data['oe_description_list'] = [
+      'type' => 'oe_description_list',
+      'field_oe_title' => 'Description list paragraph',
+      // This field will be renamed.
+      'oe_bt_orientation' => 'horizontal',
+      'field_oe_description_list_items' => [
+        // One item is enough for this test.
+        [
+          'term' => 'Aliquam ultricies',
+          'description' => 'Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.',
+        ],
+      ],
+    ];
+    $paragraphs_data['oe_facts_figures'] = [
+      'type' => 'oe_facts_figures',
+      'field_oe_title' => 'Fact and figures block',
+      'field_oe_link' => [
+        'uri' => 'https://www.readmore.com',
+        'title' => 'Read more',
+      ],
+      // This field will be renamed.
+      'oe_bt_n_columns' => 3,
+      'field_oe_paragraphs' => [
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '1529 JIRA Ticket',
+        'field_oe_subtitle' => 'Jira Tickets',
+        'field_oe_plain_text_long' => 'Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.',
+      ],
+    ];
+    $paragraphs_data['oe_links_block'] = [
+      'type' => 'oe_links_block',
+      'field_oe_text' => 'More information',
+      // These fields will be renamed.
+      'oe_bt_links_block_orientation' => 'vertical',
+      'oe_bt_links_block_background' => 'gray',
+      'field_oe_links' => [
+        // One link is enough for this test.
+        [
+          'title' => 'European Commission',
+          'uri' => 'https://example.com',
+        ],
+      ],
+    ];
+    $paragraphs_data['oe_social_media_follow'] = [
+      'type' => 'oe_social_media_follow',
+      'field_oe_title' => 'Social media title',
+      'field_oe_social_media_variant' => 'horizontal',
+      // This field will be renamed.
+      'oe_bt_links_block_background' => 'gray',
+      // One link is enough for this test.
+      'field_oe_social_media_links' => [
+        [
+          'title' => 'Email',
+          'uri' => 'mailto:example@com',
+          'link_type' => 'email',
+        ],
+      ],
+      'field_oe_social_media_see_more' => [
+        'title' => 'Other social networks',
+        'uri' => 'https://europa.eu/european-union/contact/social-networks_en',
+      ],
+    ];
+
+    $revision_ids = [];
+    foreach ($paragraphs_data as $name => $paragraph_data) {
+      $paragraph = Paragraph::create($paragraph_data);
+      $paragraph->save();
+      $revision_ids[$name] = $paragraph->getRevisionId();
+      if ($name !== 'oe_links_block') {
+        // Don't create a revision for most of the paragraphs.
+        continue;
+      }
+      // Make this paragraph a revision.
+      $paragraph->setNewRevision();
+      $paragraph->oe_bt_links_block_orientation = 'horizontal';
+      $paragraph->save();
+      $revision_ids[$name . ':modified'] = $paragraph->getRevisionId();
+    }
+
+    $legacy_field_config_ids = [
+      'paragraph.oe_description_list.oe_bt_orientation',
+      'paragraph.oe_facts_figures.oe_bt_n_columns',
+      'paragraph.oe_links_block.oe_bt_links_block_background',
+      'paragraph.oe_links_block.oe_bt_links_block_orientation',
+      'paragraph.oe_social_media_follow.oe_bt_links_block_background',
+    ];
+    $legacy_field_storage_ids = [
+      'paragraph.oe_bt_links_block_background',
+      'paragraph.oe_bt_links_block_orientation',
+      'paragraph.oe_bt_n_columns',
+      'paragraph.oe_bt_orientation',
+    ];
+    $this->assertEqualsCanonicalizing(
+      $legacy_field_config_ids,
+      array_keys(FieldConfig::loadMultiple($legacy_field_config_ids)),
+    );
+    $this->assertEqualsCanonicalizing(
+      $legacy_field_storage_ids,
+      array_keys(FieldStorageConfig::loadMultiple($legacy_field_storage_ids)),
+    );
+
+    /** @var \Drupal\Core\Extension\ModuleInstallerInterface $installer */
+    $installer = \Drupal::service('module_installer');
+    $installer->install(['oe_whitelabel_paragraphs']);
+
+    $this->assertTrue(
+      \Drupal::moduleHandler()->moduleExists('oe_whitelabel_paragraphs'),
+      "Module 'oe_whitelabel_paragraphs was successfully installed.");
+
+    $this->assertEmpty(FieldConfig::loadMultiple($legacy_field_config_ids));
+    $this->assertEmpty(FieldStorageConfig::loadMultiple($legacy_field_storage_ids));
+
+    $expected_created = [
+      'oe_description_list' => [
+        'oe_w_orientation' => 'horizontal',
+      ],
+      'oe_facts_figures' => [
+        'oe_w_n_columns' => '3',
+      ],
+      'oe_links_block' => [
+        'oe_w_links_block_orientation' => 'vertical',
+        'oe_w_links_block_background' => 'gray',
+      ],
+      'oe_links_block:modified' => [
+        'oe_w_links_block_orientation' => 'horizontal',
+        'oe_w_links_block_background' => 'gray',
+      ],
+      'oe_social_media_follow' => [
+        'oe_w_links_block_background' => 'gray',
+      ],
+    ];
+
+    $expected_deleted = [
+      'oe_description_list' => [
+        'oe_bt_orientation' => TRUE,
+      ],
+      'oe_facts_figures' => [
+        'oe_bt_n_columns' => TRUE,
+      ],
+      'oe_links_block' => [
+        'oe_bt_links_block_orientation' => TRUE,
+        'oe_bt_links_block_background' => TRUE,
+      ],
+      'oe_links_block:modified' => [
+        'oe_bt_links_block_orientation' => TRUE,
+        'oe_bt_links_block_background' => TRUE,
+      ],
+      'oe_social_media_follow' => [
+        'oe_bt_links_block_background' => TRUE,
+      ],
+    ];
+
+    $storage = \Drupal::entityTypeManager()->getStorage('paragraph');
+
+    // Produce reports instead of many individual assertions. This is less
+    // simple in code, but produces more useful output on test failure.
+    $actual_updated = [];
+    $actual_deleted = [];
+    foreach ($revision_ids as $name => $revision_id) {
+      $updated_revision = $storage->loadRevision($revision_id);
+      $this->assertNotNull($updated_revision);
+      foreach ($expected_created[$name] as $field_name => $value) {
+        if (!$updated_revision->hasField($field_name)) {
+          // The expected field was not created.
+          // Omit this entry in $actual_updated, to cause a fail below.
+          continue;
+        }
+        // The expected field was created, but the value might be wrong.
+        $actual_updated[$name][$field_name] = $updated_revision->get($field_name)->value;
+      }
+      foreach ($expected_deleted[$name] as $field_name => $deleted) {
+        $actual_deleted[$name][$field_name] = !$updated_revision->hasField($field_name);
+      }
+    }
+
+    // Compare the reports to the expected values.
+    $this->assertSame($expected_created, $actual_updated);
+    $this->assertSame($expected_deleted, $actual_deleted);
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Functional/ParagraphsTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Functional/ParagraphsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..879560768c13361acddd02af035af3ca2e52af2f
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Functional/ParagraphsTest.php
@@ -0,0 +1,330 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Functional;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests paragraphs forms.
+ */
+class ParagraphsTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'node',
+    'oe_whitelabel_paragraphs',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->createTestContentType();
+    $this->drupalLogin($this->drupalCreateUser([], '', TRUE));
+  }
+
+  /**
+   * Test Links Block paragraphs form.
+   */
+  public function testLinksBlockParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $this->getSession()->getPage()->pressButton('Add Links block');
+
+    // Assert the Links Block fields appears.
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_links][0][uri]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_links][0][title]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_text][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][oe_w_links_block_background]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][oe_w_links_block_orientation]');
+
+    $this->submitForm([], 'Add another item');
+
+    $values = [
+      'title[0][value]' => 'Test Links block node title',
+      'oe_w_paragraphs[0][subform][field_oe_text][0][value]' => 'EU Links',
+      'oe_w_paragraphs[0][subform][field_oe_links][0][uri]' => 'https://www.example.com',
+      'oe_w_paragraphs[0][subform][field_oe_links][0][title]' => 'Example link number 1',
+      'oe_w_paragraphs[0][subform][field_oe_links][1][uri]' => 'https://www.more-example.com',
+      'oe_w_paragraphs[0][subform][field_oe_links][1][title]' => 'Example link number 2',
+      'oe_w_paragraphs[0][subform][oe_w_links_block_background]' => 'gray',
+      'oe_w_paragraphs[0][subform][oe_w_links_block_orientation]' => 'vertical',
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are printed.
+    $this->assertSession()->pageTextContains('EU Links');
+    $this->assertSession()->pageTextContains('Example link number 1');
+    $this->assertSession()->pageTextContains('Example link number 2');
+  }
+
+  /**
+   * Test Social media follow paragraphs form.
+   */
+  public function testSocialMediaFollowParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $this->getSession()->getPage()->pressButton('Add Social media follow');
+
+    // Assert the Social Media Follow fields appears.
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_links][0][uri]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_links][0][title]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_links][0][link_type]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_title][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][oe_w_links_block_background]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_variant]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_see_more][0][uri]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_social_media_see_more][0][title]');
+
+    $this->submitForm([], 'Add another item');
+
+    $values = [
+      'title[0][value]' => 'Test Social Media follow Links node title',
+      'oe_w_paragraphs[0][subform][field_oe_title][0][value]' => 'EU Social Media Follow Links',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_links][0][uri]' => 'https://www.facebook.com',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_links][0][title]' => 'Example Facebook',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_links][0][link_type]' => 'facebook',
+      'oe_w_paragraphs[0][subform][oe_w_links_block_background]' => 'transparent',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_variant]' => 'horizontal',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_see_more][0][uri]' => 'https://example.com',
+      'oe_w_paragraphs[0][subform][field_oe_social_media_see_more][0][title]' => 'More channels',
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are printed.
+    $this->assertSession()->pageTextContains('EU Social Media Follow Links');
+    $this->assertSession()->pageTextContains('Example Facebook');
+    $this->assertSession()->pageTextContains('More channels');
+  }
+
+  /**
+   * Test Accordion paragraphs form.
+   */
+  public function testAccordionParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $page = $this->getSession()->getPage();
+    $page->pressButton('Add Accordion');
+
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text_long][0][value]');
+    // Assert the Icon field is not shown.
+    $this->assertSession()->fieldNotExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_icon][0][value]');
+
+    $values = [
+      'title[0][value]' => 'Test Accordion',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text][0][value]' => 'Title item 1',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text_long][0][value]' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are displayed correctly.
+    $this->assertSession()->pageTextContains('Title item 1');
+    $this->assertSession()->pageTextContains('Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
+  }
+
+  /**
+   * Test Facts and figures paragraphs form.
+   */
+  public function testFactsFiguresParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $page = $this->getSession()->getPage();
+    $page->pressButton('Add Facts and figures');
+    // Assert the Facts and figures fields are present.
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_link][0][uri]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_link][0][title]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_title][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][oe_w_n_columns][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_title][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_subtitle][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_plain_text_long][0][value]');
+
+    $values = [
+      'title[0][value]' => 'Test Fact and figures node title',
+      'oe_w_paragraphs[0][subform][field_oe_title][0][value]' => 'Fact and figures block',
+      'oe_w_paragraphs[0][subform][field_oe_link][0][uri]' => 'https://www.google.com',
+      'oe_w_paragraphs[0][subform][field_oe_link][0][title]' => 'Read more',
+      'oe_w_paragraphs[0][subform][oe_w_n_columns][0][value]' => 2,
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_title][0][value]' => "1529 JIRA Ticket",
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_subtitle][0][value]' => "Jira Tickets",
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_plain_text_long][0][value]' => "Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.",
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are displayed correctly.
+    $this->assertSession()->pageTextContains('Fact and figures block');
+    $this->assertSession()->pageTextContains('Read more');
+    $this->assertSession()->pageTextContains('1529 JIRA Ticket');
+    $this->assertSession()->pageTextContains('Jira Tickets');
+    $this->assertSession()->pageTextContains('Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.');
+  }
+
+  /**
+   * Test icon options event subscriber.
+   */
+  public function testIconOptionsEventsubscriber(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $page = $this->getSession()->getPage();
+    $page->pressButton('Add Fact');
+
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_icon]');
+    $allowed_values = [
+      '_none',
+      'arrow-down',
+      'box-arrow-up',
+      'arrow-up',
+      'book',
+      'camera',
+      'check',
+      'download',
+      'currency-euro',
+      'facebook',
+      'file',
+      'image',
+      'info',
+      'linkedin',
+      'files',
+      'rss',
+      'search',
+      'share',
+      'twitter',
+      'camera-video',
+    ];
+    foreach ($allowed_values as $allowed_value) {
+      $this->assertSession()->elementsCount('css', 'option[value="' . $allowed_value . '"]', 1);
+    }
+    $this->assertSession()->elementsCount('css', 'select#edit-oe-w-paragraphs-0-subform-field-oe-icon option', 20);
+
+  }
+
+  /**
+   * Test Description list paragraphs form.
+   */
+  public function testDescriptionListParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $this->getSession()->getPage()->pressButton('Add Description list');
+
+    $assert_session = $this->assertSession();
+    $assert_session->fieldExists('oe_w_paragraphs[0][subform][field_oe_title][0][value]');
+    $this->assertEquals([
+      'horizontal' => 'Horizontal',
+      'vertical' => 'Vertical',
+    ], $this->getOptions('oe_w_paragraphs[0][subform][oe_w_orientation]'));
+    $assert_session->fieldExists('oe_w_paragraphs[0][subform][field_oe_description_list_items][0][term]');
+    $assert_session->fieldExists('oe_w_paragraphs[0][subform][field_oe_description_list_items][0][description][value]');
+
+    $values = [
+      'title[0][value]' => 'Test Description list node title',
+      'oe_w_paragraphs[0][subform][field_oe_title][0][value]' => 'Description list paragraph',
+      'oe_w_paragraphs[0][subform][oe_w_orientation]' => 'horizontal',
+      'oe_w_paragraphs[0][subform][field_oe_description_list_items][0][term]' => 'Aliquam ultricies',
+      'oe_w_paragraphs[0][subform][field_oe_description_list_items][0][description][value]' => 'Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.',
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are displayed correctly.
+    $assert_session->pageTextContains('Description list paragraph');
+    $assert_session->pageTextContains('Aliquam ultricies');
+    $assert_session->pageTextContains('Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.');
+  }
+
+  /**
+   * Test Links Block paragraphs form.
+   */
+  public function testListingParagraph(): void {
+    $this->drupalGet('/node/add/paragraphs_test');
+    $page = $this->getSession()->getPage();
+    $page->pressButton('Add Listing item block');
+
+    // Assert the Listing fields appears.
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][variant]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_title][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_list_item_block_layout]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_link][0][uri]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_title][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text_long][0][value]');
+    $this->assertSession()->fieldExists('oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_meta][0][value]');
+    $this->assertSession()->fieldExists('files[oe_w_paragraphs_0_subform_field_oe_paragraphs_0_subform_field_oe_image_0]');
+
+    $this->submitForm([], 'Add another item');
+
+    $values = [
+      'title[0][value]' => 'Listing node title',
+      'oe_w_paragraphs[0][variant]' => 'default',
+      'oe_w_paragraphs[0][subform][field_oe_title][0][value]' => 'Listing example',
+      'oe_w_paragraphs[0][subform][field_oe_list_item_block_layout]' => 'two_columns',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_link][0][uri]'  => 'https://www.example.com',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_title][0][value]'  => 'Card title',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_text_long][0][value]'  => 'Lorem Ipsum dolor sit amet.',
+      'oe_w_paragraphs[0][subform][field_oe_paragraphs][0][subform][field_oe_meta][0][value]'  => 'label1',
+    ];
+
+    $this->submitForm($values, 'Save');
+    $this->drupalGet('/node/1');
+
+    // Assert paragraph values are displayed correctly.
+    $this->assertSession()->pageTextContains('Listing example');
+    $this->assertSession()->pageTextContains('Card title');
+    $this->assertSession()->pageTextContains('Lorem Ipsum dolor sit amet.');
+    $this->assertSession()->pageTextContains('label1');
+  }
+
+  /**
+   * Creates a node type with a paragraphs field.
+   */
+  protected function createTestContentType() {
+    $this->drupalCreateContentType([
+      'type' => 'paragraphs_test',
+      'name' => 'Paragraphs Test',
+    ]);
+
+    // Add a paragraphs field.
+    $field_storage = FieldStorageConfig::create([
+      'field_name' => 'oe_w_paragraphs',
+      'entity_type' => 'node',
+      'type' => 'entity_reference_revisions',
+      'cardinality' => '-1',
+      'settings' => [
+        'target_type' => 'paragraph',
+      ],
+    ]);
+    $field_storage->save();
+    FieldConfig::create([
+      'field_storage' => $field_storage,
+      'bundle' => 'paragraphs_test',
+      'settings' => [
+        'handler' => 'default:paragraph',
+        'handler_settings' => ['target_bundles' => NULL],
+      ],
+    ])->save();
+
+    $form_display = \Drupal::service('entity_display.repository')->getFormDisplay('node', 'paragraphs_test');
+    $form_display = $form_display->setComponent('oe_w_paragraphs', ['type' => 'oe_paragraphs_variants']);
+    $form_display->save();
+
+    $view_display = \Drupal::service('entity_display.repository')->getViewDisplay('node', 'paragraphs_test');
+    $view_display->setComponent('oe_w_paragraphs', ['type' => 'entity_reference_revisions_entity_view']);
+    $view_display->save();
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/AbstractKernelTestBase.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/AbstractKernelTestBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..437d1e649702dadc2a576cfd1ed7d2e3ae9c0706
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/AbstractKernelTestBase.php
@@ -0,0 +1,104 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel;
+
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Traits\RenderTrait;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Base class for theme's kernel tests.
+ */
+abstract class AbstractKernelTestBase extends KernelTestBase {
+
+  use RenderTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'breakpoint',
+    'image',
+    'oe_bootstrap_theme_helper',
+    'oe_whitelabel_helper',
+    'responsive_image',
+    'system',
+    'ui_patterns',
+    'ui_patterns_settings',
+    'ui_patterns_library',
+    'user',
+    'node',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('user');
+    $this->installSchema('system', 'sequences');
+    $this->installConfig(['user']);
+    $this->installConfig([
+      'system',
+      'image',
+      'responsive_image',
+      'oe_bootstrap_theme_helper',
+      'oe_whitelabel_helper',
+    ]);
+
+    $this->container->get('theme_installer')->install(['oe_whitelabel']);
+    $this->config('system.theme')->set('default', 'oe_whitelabel')->save();
+    $this->container->set('theme.registry', NULL);
+
+    // Call the install hook of the User module which creates the Anonymous user
+    // and User 1. This is needed because the Anonymous user is loaded to
+    // provide the current User context which is needed in places like route
+    // enhancers.
+    // @see CurrentUserContext::getRuntimeContexts().
+    // @see EntityConverter::convert().
+    module_load_include('install', 'user');
+    user_install();
+  }
+
+  /**
+   * Get fixture content.
+   *
+   * @param string $filepath
+   *   File path.
+   *
+   * @return array
+   *   A set of test data.
+   */
+  protected function getFixtureContent(string $filepath): array {
+    return Yaml::parse(file_get_contents(__DIR__ . "/fixtures/{$filepath}"));
+  }
+
+  /**
+   * Builds and returns the renderable array for a block.
+   *
+   * @param string $block_id
+   *   The ID of the block.
+   * @param array $config
+   *   An array of configuration.
+   *
+   * @return array
+   *   A renderable array representing the content of the block.
+   */
+  protected function buildBlock(string $block_id, array $config): array {
+    /** @var \Drupal\Core\Block\BlockBase $plugin */
+    $plugin = $this->container->get('plugin.manager.block')->createInstance($block_id, $config);
+
+    // Inject runtime contexts.
+    if ($plugin instanceof ContextAwarePluginInterface) {
+      $contexts = $this->container->get('context.repository')->getRuntimeContexts($plugin->getContextMapping());
+      $this->container->get('context.handler')->applyContextMapping($plugin, $contexts);
+    }
+
+    return $plugin->build();
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ContentRowTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ContentRowTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbd451ed3a54f536926ac0a4379219d92ccc3eda
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ContentRowTest.php
@@ -0,0 +1,184 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\Entity\Paragraph;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the "Content row" paragraph, "Inpage navigation" variant.
+ */
+class ContentRowTest extends ParagraphsTestBase {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testWithInpageNavigationRendering(): void {
+    $paragraph_fact = [
+      Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '1529 JIRA Ticket',
+        'field_oe_subtitle' => 'Jira Tickets',
+        'field_oe_plain_text_long' => 'Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '337 Features',
+        'field_oe_subtitle' => 'Feature tickets',
+        'field_oe_plain_text_long' => 'Turpis varius congue venenatis, erat dui feugiat felis.',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '107 Tests',
+        'field_oe_subtitle' => 'Test tickets',
+        'field_oe_plain_text_long' => 'Cras vestibulum efficitur mi, quis porta tellus rutrum ut. Quisque at pulvinar sem.',
+      ]),
+    ];
+
+    $paragraph_accordion = [
+      Paragraph::create([
+        'type' => 'oe_accordion_item',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_text' => 'Accordion item 1',
+        'field_oe_text_long' => 'Aenean at viverra tellus. Donec egestas ut ligula a condimentum. Cras sapien nulla, ornare eget lobortis vulputate, bibendum nec tellus. Fusce tristique diam quis mauris vehicula eleifend. Maecenas vitae luctus mi. Sed accumsan fermentum fermentum. Ut tristique quam at aliquam viverra. Suspendisse pulvinar risus tristique augue elementum, nec blandit sem mattis',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_accordion_item',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_text' => 'Accordion item 2',
+        'field_oe_text_long' => 'Morbi pretium efficitur dolor, a vulputate sem vulputate quis. Sed dictum massa eu nulla finibus, et porta dolor efficitur. Mauris pharetra dui sed consequat faucibus. Pellentesque felis nisi, fringilla non tortor ac, laoreet feugiat ante. Curabitur vel gravida augue. Nullam erat dui, viverra a arcu non, tincidunt pulvinar tortor. Maecenas non libero consequat massa ornare posuere. Quisque ultrices ullamcorper leo, non vulputate felis vestibulum a. Nam eu tellus enim.',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_accordion_item',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_text' => 'Accordion item 3',
+        'field_oe_text_long' => 'Mauris accumsan vulputate imperdiet. Aenean nec metus sem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum maximus placerat orci, a placerat dolor iaculis vel. Nam pulvinar elementum odio ut tempor. In fermentum neque ut placerat rutrum.',
+      ]),
+    ];
+
+    $sub_paragraphs = [
+      Paragraph::create([
+        'type' => 'oe_rich_text',
+        'field_oe_title' => 'Title rich text test 1',
+        'field_oe_text_long' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ornare et elit a dictum. Maecenas lacinia eros quis eros iaculis, sit amet bibendum massa facilisis. Integer arcu nisl, fringilla nec quam vel, tincidunt maximus ex. Suspendisse ac arcu efficitur, feugiat tellus vel, viverra sapien. Etiam vitae condimentum lorem. Nulla congue ligula lacinia efficitur tempus. Duis vitae auctor enim. Nulla iaculis, diam et sagittis scelerisque, est mauris luctus sem, a imperdiet lacus diam eu dui. Morbi accumsan, augue eu gravida elementum, libero mi blandit odio, eu fringilla nunc ipsum non tellus. Suspendisse dapibus elit at lobortis pretium. Quisque vestibulum ut purus sit amet molestie. Sed eget volutpat justo, vel varius augue. Vestibulum vel risus facilisis, feugiat sem aliquam, lobortis ante.',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_links_block',
+        'field_oe_text' => 'Links block test',
+        'oe_w_links_block_orientation' => 'vertical',
+        'oe_w_links_block_background' => 'gray',
+        'field_oe_links' => [
+          [
+            'title' => 'Example 2',
+            'uri' => 'https://example2.com',
+          ],
+          [
+            'title' => 'Example 3',
+            'uri' => 'https://example3.com',
+          ],
+          [
+            'title' => 'Example 4',
+            'uri' => 'https://example4.com',
+          ],
+        ],
+      ]),
+      Paragraph::create([
+        'type' => 'oe_facts_figures',
+        'field_oe_title' => 'Facts and Figures test',
+        'field_oe_link' => [
+          'uri' => 'https://www.readmore.com',
+          'title' => 'Read more',
+        ],
+        'field_oe_paragraphs' => $paragraph_fact,
+        'field_oe_list_item_block_layout' => 3,
+      ]),
+      Paragraph::create([
+        'type' => 'oe_quote',
+        'field_oe_text' => 'Quote 1',
+        'field_oe_plain_text_long' => 'Maecenas id urna eleifend, elementum sapien vitae, semper massa. Curabitur mi leo, sagittis eget euismod egestas, ornare nec justo.',
+      ]),
+      Paragraph::create([
+        'type' => 'oe_social_media_follow',
+        'field_oe_title' => 'Social media block',
+        'field_oe_social_media_variant' => 'horizontal',
+        'oe_w_links_block_background' => 'gray',
+        'field_oe_social_media_links' => [
+          [
+            'title' => 'Email',
+            'uri' => 'mailto:example@com',
+            'link_type' => 'email',
+          ],
+          [
+            'title' => 'Facebook',
+            'uri' => 'https://facebook.com',
+            'link_type' => 'facebook',
+          ],
+        ],
+        'field_oe_social_media_see_more' => [
+          'title' => 'Other social networks',
+          'uri' => 'https://europa.eu/european-union/contact/social-networks_en',
+        ],
+      ]),
+      Paragraph::create([
+        'type' => 'oe_accordion',
+        'field_oe_paragraphs' => $paragraph_accordion,
+      ]),
+    ];
+
+    $paragraph = Paragraph::create([
+      'type' => 'oe_content_row',
+      'field_oe_title' => 'Page content',
+      'field_oe_paragraphs' => $sub_paragraphs,
+      'oe_paragraphs_variant' => 'inpage_navigation',
+    ]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row > div > nav.bcl-inpage-navigation'));
+    $this->assertCount(8, $crawler->filter('p'));
+    // Assert the left column navigation.
+    $left = $crawler->filter('div.col-md-3.d-none.d-md-block');
+    $nav = $left->filter('nav.bcl-inpage-navigation');
+    $this->assertCount(1, $nav);
+    $h5 = $nav->filter('h5');
+    $this->assertSame('Page content', $h5->text());
+    $ul = $left->filter('ul.nav.nav-pills.flex-column');
+    $this->assertCount(1, $ul);
+    $links = $ul->filter('li.nav-item a.nav-link');
+    $this->assertCount(3, $links);
+    $this->assertSame('Title rich text test 1', $links->eq(0)->text());
+    $this->assertSame('Facts and Figures test', $links->eq(1)->text());
+    $this->assertSame('Social media block', $links->eq(2)->text());
+    // Assert the paragraphs where added into the right side column.
+    $content = $crawler->filter('div.col-md-9');
+    $this->assertCount(1, $content);
+    $rich_text_title = $content->filter('h4.fw-bold.mb-4');
+    $this->assertSame('Title rich text test 1', trim($rich_text_title->text()));
+    $links_block_title = $content->filter('h2.fw-bold.pb-3.mb-3.border-bottom');
+    $this->assertSame('Links block test', $links_block_title->text());
+    $facts_figures = $content->filter('div.bcl-fact-figures--default');
+    $this->assertStringContainsString('Facts and Figures test', $facts_figures->filter('h2.fw-bold')->text());
+    $blockquote_blockquote = $content->filter('blockquote.blockquote');
+    $this->assertStringContainsString('Maecenas id urna eleifend', $blockquote_blockquote->text());
+    $blockquote_footer = $content->filter('figcaption.blockquote-footer');
+    $this->assertSame('Quote 1', trim($blockquote_footer->text()));
+    $social_media_title = $content->filter('h2.fw-bold.pb-3.mb-3.border-bottom')->eq(1);
+    $this->assertStringContainsString('Social media block', $social_media_title->text());
+    $accordion_items = $content->filter('.accordion-item');
+    $this->assertStringContainsString('Accordion item 1', $accordion_items->eq(0)->text());
+    $this->assertStringContainsString('Accordion item 2', $accordion_items->eq(1)->text());
+    $this->assertStringContainsString('Accordion item 3', $accordion_items->eq(2)->text());
+    // Check that the wrappers where added to the correct paragraphs.
+    $this->assertSame('bcl-inpage-item-1', $rich_text_title->parents()->eq(0)->attr('id'));
+    $this->assertSame('bcl-inpage-item-6', $facts_figures->parents()->eq(0)->attr('id'));
+    $this->assertSame('bcl-inpage-item-8', $social_media_title->parents()->eq(1)->attr('id'));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DescriptionListTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DescriptionListTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d96781b19d9c9b1c5cdcadc5b9fcdf5859b1c1dd
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DescriptionListTest.php
@@ -0,0 +1,92 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\Entity\Paragraph;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the "Description list" paragraphs.
+ */
+class DescriptionListTest extends ParagraphsTestBase {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    // Create Description list paragraph with horizontal variant.
+    $paragraph = Paragraph::create([
+      'type' => 'oe_description_list',
+      'field_oe_title' => 'Description list paragraph',
+      'oe_w_orientation' => 'horizontal',
+      'field_oe_description_list_items' => [
+        0 => [
+          'term' => 'Aliquam ultricies',
+          'description' => 'Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.',
+        ],
+        1 => [
+          'term' => 'Etiam lacinia',
+          'description' => 'Quisque tempor sollicitudin lacinia. Morbi imperdiet nulla et nunc aliquet, vel lobortis nunc cursus. Mauris vitae hendrerit felis.',
+        ],
+      ],
+    ]);
+    $paragraph->save();
+
+    // Testing: Description list paragraph with horizontal variant.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('h4'));
+    $this->assertCount(1, $crawler->filter('dl.d-md-grid.grid-3-9'));
+    $this->assertCount(2, $crawler->filter('dd'));
+    $this->assertCount(2, $crawler->filter('dt'));
+
+    $title = $crawler->filter('h4.fw-bold.mb-4');
+    $this->assertEquals('Description list paragraph', $title->text());
+
+    $term_1 = $crawler->filter('dl > div:nth-child(1) > dt');
+    $this->assertEquals('Aliquam ultricies', $term_1->text());
+    $description_1 = $crawler->filter('dl > div:nth-child(1) + dd');
+    $this->assertEquals(
+      'Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.',
+      $description_1->text()
+    );
+
+    $term_2 = $crawler->filter('dl > div:nth-child(3) > dt');
+    $this->assertEquals('Etiam lacinia', $term_2->text());
+    $description_2 = $crawler->filter('dl > div:nth-child(3) + dd');
+    $this->assertEquals(
+      'Quisque tempor sollicitudin lacinia. Morbi imperdiet nulla et nunc aliquet, vel lobortis nunc cursus. Mauris vitae hendrerit felis.',
+      $description_2->text()
+    );
+
+    // Testing: Description list paragraph with vertical variant.
+    $paragraph->get('oe_w_orientation')->setValue('vertical');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $title = $crawler->filter('h4.fw-bold.mb-4');
+    $this->assertEquals('Description list paragraph', $title->text());
+
+    $term_1 = $crawler->filter('dl > dt:nth-child(1)');
+    $this->assertEquals('Aliquam ultricies', $term_1->text());
+    $description_1 = $crawler->filter('dl > dt:nth-child(1) + dd');
+    $this->assertEquals(
+      'Donec et leo ac velit posuere tempor mattis ac mi. Vivamus nec dictum lectus. Aliquam ultricies placerat eros, vitae ornare sem.',
+      $description_1->text()
+    );
+
+    $term_2 = $crawler->filter('dl > dt:nth-child(3)');
+    $this->assertEquals('Etiam lacinia', $term_2->text());
+    $description_2 = $crawler->filter('dl > dt:nth-child(3) + dd');
+    $this->assertEquals(
+      'Quisque tempor sollicitudin lacinia. Morbi imperdiet nulla et nunc aliquet, vel lobortis nunc cursus. Mauris vitae hendrerit felis.',
+      $description_2->text()
+    );
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DocumentParagraphTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DocumentParagraphTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ca6a7926f94c630e43f13520356861af76e83f7
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/DocumentParagraphTest.php
@@ -0,0 +1,234 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\Core\Site\Settings;
+use Drupal\file\Entity\File;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\media\Entity\Media;
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\oe_bootstrap_theme\PatternAssertion\FilePatternAssert;
+use Drupal\Tests\user\Traits\UserCreationTrait;
+use Drupal\user\Entity\User;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the document paragraph.
+ */
+class DocumentParagraphTest extends ParagraphsTestBase {
+
+  use UserCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'content_translation',
+    'file_link_test',
+    'language',
+    'node',
+    'oe_paragraphs_document',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    // The node dependency is wrongfully forced by oe_media_media_access().
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('media');
+    $this->installConfig([
+      'content_translation',
+      'language',
+      'media',
+      'oe_media',
+    ]);
+
+    $this->container->get('module_handler')->loadInclude('oe_paragraphs_media_field_storage', 'install');
+    oe_paragraphs_media_field_storage_install(FALSE);
+    $this->installConfig(['oe_paragraphs_document']);
+
+    ConfigurableLanguage::createFromLangcode('it')->save();
+    ConfigurableLanguage::createFromLangcode('es')->save();
+
+    // Enable translations for the document media bundle.
+    $this->container->get('content_translation.manager')->setEnabled('media', 'document', TRUE);
+    // Make fields translatable.
+    $field_ids = [
+      'media.document.oe_media_file_type',
+      'media.document.oe_media_remote_file',
+      'media.document.oe_media_file',
+    ];
+    foreach ($field_ids as $field_id) {
+      $field_config = $this->container->get('entity_type.manager')->getStorage('field_config')->load($field_id);
+      $field_config->set('translatable', TRUE)->save();
+    }
+    $this->container->get('router.builder')->rebuild();
+
+    // Simulate the presence of test remote files. This avoids real requests to
+    // external websites.
+    $settings = Settings::getAll();
+    $settings['file_link_test_middleware'] = [
+      'http://oe_whitelabel.drupal/spanish-document.txt' => [
+        'status' => 200,
+        'headers' => [
+          'Content-Type' => 'text/plain',
+          'Content-Length' => 45187,
+        ],
+      ],
+      'http://oe_whitelabel.drupal/spreadsheet.xls' => [
+        'status' => 200,
+        'headers' => [
+          'Content-Type' => 'application/vnd.ms-excel',
+          'Content-Length' => 78459784,
+        ],
+      ],
+    ];
+    new Settings($settings);
+
+    // Tests need to run with user 1 as access checks prevent entity reference
+    // rendering otherwise.
+    $this->setCurrentUser(User::load(1));
+  }
+
+  /**
+   * Tests the file paragraph rendering.
+   */
+  public function testRendering(): void {
+    $uri_en = $this->container->get('file_system')->copy(
+      $this->container->get('extension.list.module')->getPath('oe_media') . '/tests/fixtures/sample.pdf',
+      'public://test.pdf'
+    );
+    $pdf_en = File::create(['uri' => $uri_en]);
+    $pdf_en->save();
+
+    $local_media = Media::create([
+      'bundle' => 'document',
+      'name' => 'Local PDF file',
+      'oe_media_file_type' => 'local',
+      'oe_media_file' => [
+        'target_id' => $pdf_en->id(),
+      ],
+    ]);
+    $local_media->save();
+
+    $paragraph = Paragraph::create([
+      'type' => 'oe_document',
+      'field_oe_media' => [
+        'target_id' => $local_media->id(),
+      ],
+    ]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+    $paragraph_wrapper = $crawler->filter('.paragraph');
+    $this->assertCount(1, $paragraph_wrapper);
+
+    $expected = [
+      'file' => [
+        'title' => 'Local PDF file',
+        'language' => 'English',
+        'url' => file_create_url($uri_en),
+        'meta' => '(2.96 KB - PDF)',
+        'icon' => 'file-pdf-fill',
+      ],
+      'translations' => NULL,
+      'link_label' => 'Download',
+    ];
+    $assert = new FilePatternAssert();
+    $assert->assertPattern($expected, $paragraph_wrapper->html());
+
+    // Add an Italian translation for the media.
+    $uri_it = $this->container->get('file_system')->copy(
+      $this->container->get('extension.list.module')->getPath('oe_media') . '/tests/fixtures/sample.pdf',
+      'public://test_it.pdf'
+    );
+    $pdf_it = File::create(['uri' => $uri_it]);
+    $pdf_it->save();
+    $local_media->addTranslation('it', [
+      'name' => 'Italian translation',
+      'oe_media_file_type' => 'local',
+      'oe_media_file' => [
+        'target_id' => $pdf_it->id(),
+      ],
+    ]);
+    $local_media->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+    $paragraph_wrapper = $crawler->filter('.paragraph');
+    $this->assertCount(1, $paragraph_wrapper);
+    $expected['translations'] = [
+      [
+        'title' => 'Italian translation',
+        'language' => 'Italian',
+        'url' => file_create_url($uri_it),
+        'meta' => '(2.96 KB - PDF)',
+      ],
+    ];
+    $assert->assertPattern($expected, $paragraph_wrapper->html());
+
+    // Add a Spanish translation that points to a remote file.
+    $local_media->addTranslation('es', [
+      'name' => 'Spanish translation',
+      'oe_media_file_type' => 'remote',
+      'oe_media_remote_file' => 'http://oe_whitelabel.drupal/spanish-document.txt',
+    ]);
+    $local_media->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+    $paragraph_wrapper = $crawler->filter('.paragraph');
+    $this->assertCount(1, $paragraph_wrapper);
+    $expected['translations'][] = [
+      'title' => 'Spanish translation',
+      'language' => 'Spanish',
+      'url' => 'http://oe_whitelabel.drupal/spanish-document.txt',
+      'meta' => '(44.13 KB - TXT)',
+    ];
+    $assert->assertPattern($expected, $paragraph_wrapper->html());
+
+    // Test a remote document as main file, to make sure that the
+    // DocumentMediaWrapper class is tested in all scenarios.
+    $remote_media = Media::create([
+      'bundle' => 'document',
+      'name' => 'Remote XLS file',
+      'oe_media_file_type' => 'remote',
+      'oe_media_remote_file' => 'http://oe_whitelabel.drupal/spreadsheet.xls',
+    ]);
+    $remote_media->save();
+
+    $paragraph = Paragraph::create([
+      'type' => 'oe_document',
+      'field_oe_media' => [
+        'target_id' => $remote_media->id(),
+      ],
+    ]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+    $paragraph_wrapper = $crawler->filter('.paragraph');
+    $this->assertCount(1, $paragraph_wrapper);
+
+    $expected = [
+      'file' => [
+        'title' => 'Remote XLS file',
+        'language' => 'English',
+        'url' => 'http://oe_whitelabel.drupal/spreadsheet.xls',
+        'meta' => '(74.83 MB - XLS)',
+        'icon' => 'file-excel-fill',
+      ],
+      'translations' => NULL,
+      'link_label' => 'Download',
+    ];
+    $assert = new FilePatternAssert();
+    $assert->assertPattern($expected, $paragraph_wrapper->html());
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/EntityReferenceRevisionTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/EntityReferenceRevisionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f7e0668028a098635fd4aaa57ab13bc53a197a1
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/EntityReferenceRevisionTest.php
@@ -0,0 +1,107 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\node\Entity\Node;
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
+use Drupal\Tests\user\Traits\UserCreationTrait;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the rendering of the entity reference fields for paragraphs.
+ */
+class EntityReferenceRevisionTest extends ParagraphsTestBase {
+
+  use ContentTypeCreationTrait;
+  use UserCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+
+    $this->createContentType([
+      'type' => 'paragraphs_test',
+      'name' => 'Paragraphs Test',
+    ]);
+    $field_storage = FieldStorageConfig::create([
+      'field_name' => 'test_paragraphs',
+      'entity_type' => 'node',
+      'type' => 'entity_reference_revisions',
+      'cardinality' => '-1',
+      'settings' => [
+        'target_type' => 'paragraph',
+      ],
+    ]);
+    $field_storage->save();
+    FieldConfig::create([
+      'field_storage' => $field_storage,
+      'bundle' => 'paragraphs_test',
+      'settings' => [
+        'handler' => 'default:paragraph',
+        'handler_settings' => ['target_bundles' => NULL],
+      ],
+    ])->save();
+
+    $this->container->get('theme_installer')->install(['oe_whitelabel']);
+    $this->config('system.theme')->set('default', 'oe_whitelabel')->save();
+
+    $this->setCurrentUser($this->createUser([], '', TRUE));
+  }
+
+  /**
+   * Test the rendering of an entity reference revision field.
+   */
+  public function testEntityReferenceRevisionField(): void {
+    $paragraph1 = Paragraph::create([
+      'type' => 'oe_links_block',
+      'field_oe_text' => 'More information',
+      'oe_w_links_block_orientation' => 'vertical',
+      'oe_w_links_block_background' => 'gray',
+      'field_oe_links' => [
+        [
+          'title' => 'European Commission',
+          'uri' => 'https://example.com',
+        ],
+      ],
+    ]);
+    $paragraph1->save();
+
+    $paragraph2 = Paragraph::create([
+      'type' => 'oe_rich_text',
+      'field_oe_title' => 'Rich text example',
+    ]);
+    $paragraph2->save();
+
+    /** @var \Drupal\node\Entity\Node $node */
+    $node = Node::create([
+      'type' => 'paragraphs_test',
+      'title' => 'Test node',
+      'test_paragraphs' => [$paragraph1, $paragraph2],
+      'uid' => 0,
+      'status' => 1,
+    ]);
+    $node->save();
+
+    $build = $node->get('test_paragraphs')->view();
+    $html = $this->render($build);
+    $crawler = new Crawler($html);
+
+    $wrappers = $crawler->filter('div.my-4');
+    $this->assertCount(2, $wrappers);
+    $rich_text = $wrappers->eq(1);
+    // Assert the paragraphs where rendered.
+    $this->assertStringContainsString('European Commission', $wrappers->eq(0)->text());
+    $this->assertStringContainsString('Rich text example', $rich_text->text());
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/FactsFiguresTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/FactsFiguresTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..23633bad9dd45c4a7f2d8ad93965115ad1cb1021
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/FactsFiguresTest.php
@@ -0,0 +1,211 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Symfony\Component\DomCrawler\Crawler;
+use Drupal\paragraphs\Entity\Paragraph;
+
+/**
+ * Tests the "Facts and Figures" paragraphs.
+ */
+class FactsFiguresTest extends ParagraphsTestBase {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    // Create Fact paragraphs.
+    $paragraph_fact =
+    [
+      0 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '1529 JIRA Ticket',
+        'field_oe_subtitle' => 'Jira Tickets',
+        'field_oe_plain_text_long' => 'Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.',
+      ]),
+      1 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '337 Features',
+        'field_oe_subtitle' => 'Feature tickets',
+        'field_oe_plain_text_long' => 'Turpis varius congue venenatis, erat dui feugiat felis.',
+      ]),
+      2 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '107 Tests',
+        'field_oe_subtitle' => 'Test tickets',
+        'field_oe_plain_text_long' => 'Cras vestibulum efficitur mi, quis porta tellus rutrum ut. Quisque at pulvinar sem.',
+      ]),
+      3 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '5670 Variants',
+        'field_oe_subtitle' => 'Test variants',
+        'field_oe_plain_text_long' => 'Aliquam lacinia diam eu sem malesuada, in interdum ante bibendum.',
+      ]),
+      4 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '345 Dev Ticket',
+        'field_oe_subtitle' => 'Jira ticket',
+        'field_oe_plain_text_long' => 'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis nec lectus tortor.',
+      ]),
+      5 => Paragraph::create([
+        'type' => 'oe_fact',
+        'field_oe_icon' => 'box-arrow-up',
+        'field_oe_title' => '43 Components',
+        'field_oe_subtitle' => 'Figma components',
+        'field_oe_plain_text_long' => 'Sed efficitur bibendum rutrum. Nunc feugiat congue augue ac consectetur.',
+      ]),
+    ];
+    // Create Facts and figures paragraph.
+    $paragraph = Paragraph::create([
+      'type' => 'oe_facts_figures',
+      'field_oe_title' => 'Fact and figures block',
+      'field_oe_link' => [
+        'uri' => 'https://www.readmore.com',
+        'title' => 'Read more',
+      ],
+      'oe_w_n_columns' => 3,
+      'field_oe_paragraphs' => $paragraph_fact,
+    ]);
+    $paragraph->save();
+
+    // Testing: Facts and figures - Default layout.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.bcl-fact-figures.bcl-fact-figures--default'));
+    $this->assertCount(1, $crawler->filter('h2.fw-bold'));
+    $this->assertCount(1, $crawler->filter('div.row-cols-md-3.row'));
+    $this->assertCount(6, $crawler->filter('svg.bi.icon--l'));
+    $this->assertCount(6, $crawler->filter('h4.fw-bold'));
+    $this->assertCount(6, $crawler->filter('h5.fw-bold'));
+    $this->assertCount(6, $crawler->filter('div.col'));
+
+    $link = $crawler->filter('a[href="https://www.readmore.com"]');
+    $this->assertStringContainsString(
+      'Read more',
+      $link->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(1) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '1529 JIRA Ticket',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(1) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Jira Tickets',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(1) > p');
+    $this->assertStringContainsString(
+      'Nunc condimentum sapien ut nibh finibus suscipit vitae at justo. Morbi quis odio faucibus, commodo tortor id, elementum libero.',
+      $description_fact->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(2) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '337 Features',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(2) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Feature tickets',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(2) > p');
+    $this->assertStringContainsString(
+      'Turpis varius congue venenatis, erat dui feugiat felis.',
+      $description_fact->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(3) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '107 Tests',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(3) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Test tickets',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(3) > p');
+    $this->assertStringContainsString(
+      'Cras vestibulum efficitur mi, quis porta tellus rutrum ut. Quisque at pulvinar sem.',
+      $description_fact->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(4) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '5670 Variants',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(4) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Test variants',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(4) > p');
+    $this->assertStringContainsString(
+      'Aliquam lacinia diam eu sem malesuada, in interdum ante bibendum.',
+      $description_fact->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(5) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '345 Dev Ticket',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(5) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Jira ticket',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(5) > p');
+    $this->assertStringContainsString(
+      'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis nec lectus tortor.',
+      $description_fact->html()
+    );
+
+    $title_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(6) > h4.text-capitalize.fw-bold');
+    $this->assertStringContainsString(
+      '43 Components',
+      $title_fact->html()
+    );
+    $subtitle_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(6) >  h5.fw-bold');
+    $this->assertStringContainsString(
+      'Figma components',
+      $subtitle_fact->html()
+    );
+    $description_fact = $crawler->filter('div.row-cols-md-3.row > div.col:nth-child(6) > p');
+    $this->assertStringContainsString(
+      'Sed efficitur bibendum rutrum. Nunc feugiat congue augue ac consectetur.',
+      $description_fact->html()
+    );
+
+    // Testing: 2 columns.
+    $paragraph->get('oe_w_n_columns')->setValue('2');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row-cols-md-2.row'));
+
+    // Testing: 1 columns.
+    $paragraph->get('oe_w_n_columns')->setValue('1');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row-cols-md-1.row'));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/LinksBlockTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/LinksBlockTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3cf89e73b72fe0ef1446ef1397b2a8501dc4742
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/LinksBlockTest.php
@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\oe_whitelabel_paragraphs\Kernel\PatternAssertions\LinksBlockAssertion;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the "Social media follow" paragraphs.
+ */
+class LinksBlockTest extends LinksBlockAssertion {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    // Create Links Block paragraph.
+    $paragraph = Paragraph::create([
+      'type' => 'oe_links_block',
+      'field_oe_text' => 'More information',
+      'oe_w_links_block_orientation' => 'vertical',
+      'oe_w_links_block_background' => 'gray',
+      'field_oe_links' => $this->getBlockLinks(),
+    ]);
+    $paragraph->save();
+
+    // Testing: LinksBlock vertical gray.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundGray($crawler);
+    $this->assertLinksBlockRendering($crawler);
+    $this->assertVerticalLinks($crawler);
+
+    // Testing: LinksBlock horizontal gray.
+    $paragraph->get('oe_w_links_block_orientation')->setValue('horizontal');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundGray($crawler);
+    $this->assertLinksBlockRendering($crawler);
+    $this->assertHorizontalLinks($crawler, FALSE);
+
+    // Testing: LinksBlock vertical transparent.
+    $paragraph->get('oe_w_links_block_orientation')->setValue('vertical');
+    $paragraph->get('oe_w_links_block_background')->setValue('transparent');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundTransparent($crawler);
+    $this->assertLinksBlockRendering($crawler);
+    $this->assertVerticalLinks($crawler);
+
+    // Testing: LinksBlock horizontal transparent.
+    $paragraph->get('oe_w_links_block_orientation')->setValue('horizontal');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundTransparent($crawler);
+    $this->assertLinksBlockRendering($crawler);
+    $this->assertHorizontalLinks($crawler, FALSE);
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ListingParagraphsTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ListingParagraphsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2fe6ab379fddbf50e35a73265d5e1ffc9277e747
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ListingParagraphsTest.php
@@ -0,0 +1,194 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\node\Entity\Node;
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\oe_whitelabel_paragraphs\Kernel\PatternAssertions\ListingAssertion;
+use Drupal\Tests\TestFileCreationTrait;
+use Symfony\Component\DomCrawler\Crawler;
+use Drupal\Tests\node\Traits\NodeCreationTrait;
+use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
+use Drupal\file\Entity\File;
+
+/**
+ * Tests the rendering of paragraph Listing.
+ */
+class ListingParagraphsTest extends ParagraphsTestBase {
+
+  use NodeCreationTrait;
+  use ContentTypeCreationTrait;
+  use TestFileCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('node');
+    $this->installSchema('node', ['node_access']);
+  }
+
+  /**
+   * Test List Items Block paragraph rendering.
+   */
+  public function testListing(): void {
+
+    // Create a sample media entity to be embedded.
+    $image_file = File::create([
+      'uri' => $this->getTestFiles('image')[0]->uri,
+    ]);
+    $image_file->setPermanent();
+    $image_file->save();
+
+    $this->createContentType([
+      'type' => 'article',
+      'name' => 'Article',
+    ]);
+
+    $node = $this->createNode([
+      'created' => 1636977600,
+      'type' => 'article',
+    ]);
+    $nid = (int) $node->id();
+
+    $paragraph_storage = $this->container->get('entity_type.manager')->getStorage('paragraph');
+    $paragraph = $paragraph_storage->create([
+      'type' => 'oe_list_item_block',
+      'oe_paragraphs_variant' => 'default',
+      'field_oe_list_item_block_layout' => 'one_column',
+      'field_oe_title' => 'Listing item block title',
+      'field_oe_paragraphs' => $this->createListItems($image_file, $node),
+    ]);
+    $paragraph->save();
+
+    // Testing Default 1 col.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert = new ListingAssertion();
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertDefaultListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--default-1-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1'));
+    $this->assertCount(6, $crawler->filter('div.col-md-3.col-lg-2.rounded'));
+    $this->assertCount(6, $crawler->filter('div.col-md-9.col-lg-10'));
+
+    // Testing Default 2 col.
+    $paragraph->get('field_oe_list_item_block_layout')->setValue('two_columns');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertDefaultListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--default-2-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1.row-cols-md-2'));
+    $this->assertCount(6, $crawler->filter('div.col-xl-3.col-md-5'));
+    $this->assertCount(6, $crawler->filter('div.col-xl-9.col-md-7'));
+
+    // Testing Default 3 col.
+    $paragraph->get('field_oe_list_item_block_layout')->setValue('three_columns');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertDefaultListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--default-3-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1.row-cols-md-2.row-cols-xl-3'));
+    $this->assertCount(6, $crawler->filter('div.col-lg-4.col-md-6'));
+    $this->assertCount(6, $crawler->filter('div.col-lg-8.col-md-6'));
+
+    // Testing Highlight 1 col.
+    $paragraph->get('oe_paragraphs_variant')->setValue('highlight');
+    $paragraph->get('field_oe_list_item_block_layout')->setValue('one_column');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertHighlightListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--highlight-1-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1'));
+    $this->assertCount(6, $crawler->filter('div.col.mt-4-5'));
+    $this->assertCount(6, $crawler->filter('div.card-body'));
+
+    // Testing Highlight 2 col.
+    $paragraph->get('field_oe_list_item_block_layout')->setValue('two_columns');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertHighlightListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--highlight-2-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1.row-cols-md-2'));
+    $this->assertCount(6, $crawler->filter('div.listing-item--highlight'));
+    $this->assertCount(6, $crawler->filter('div.card-body'));
+
+    // Testing Highlight 3 col.
+    $paragraph->get('field_oe_list_item_block_layout')->setValue('three_columns');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $assert->assertListingRendering($crawler, $nid);
+    $assert->assertHighlightListingRendering($crawler, $image_file);
+    $this->assertCount(1, $crawler->filter('div.bcl-listing--highlight-3-col'));
+    $this->assertCount(1, $crawler->filter('div.row.row-cols-1.row-cols-md-3'));
+    $this->assertCount(6, $crawler->filter('div.listing-item--highlight'));
+    $this->assertCount(6, $crawler->filter('div.card-body'));
+  }
+
+  /**
+   * Assert default variant of Listing is rendering correctly.
+   *
+   * @param \Drupal\file\Entity\File $image_file
+   *   Image file to be added to the list item.
+   * @param \Drupal\node\Entity\Node $node
+   *   A Node entity.
+   */
+  protected function createListItems(File $image_file, Node $node): array {
+    $items = [];
+    for ($i = 1; $i <= 6; $i++) {
+      $paragraph = Paragraph::create([
+        'type' => 'oe_list_item',
+        'oe_paragraphs_variant' => 'default',
+        'field_oe_title' => 'Item title ' . $i,
+        'field_oe_text_long' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ut ex tristique, dignissim sem ac, bibendum est. ' . $i,
+        'field_oe_link' => [
+          'uri' => 'entity:node/' . $node->id(),
+          'title' => 'Example ' . $i,
+        ],
+        'field_oe_image' => [
+          'alt' => 'Alt for image ' . $i,
+          'target_id' => $image_file->id(),
+        ],
+        'field_oe_date' => '2011-11-13',
+        'field_oe_meta' => [
+          0 => [
+            'value' => 'Label 1 - ' . $i,
+          ],
+          1 => [
+            'value' => 'Label 2 - ' . $i,
+          ],
+        ],
+      ]);
+      $paragraph->save();
+      $items[$i] = $paragraph;
+    }
+
+    return $items;
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b434cda9af393e61c16a8b5cb6f70e31e2e6bd3c
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/MediaParagraphsTest.php
@@ -0,0 +1,644 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\Core\Url;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the rendering of paragraph types with media fields.
+ */
+class MediaParagraphsTest extends ParagraphsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->container->get('module_handler')->loadInclude('oe_paragraphs_media_field_storage', 'install');
+    oe_paragraphs_media_field_storage_install(FALSE);
+    $this->installEntitySchema('media');
+    $this->installConfig([
+      'media',
+      'oe_media',
+      'oe_paragraphs_media',
+      'media_avportal',
+      'oe_media_avportal',
+      'oe_paragraphs_banner',
+      'oe_paragraphs_iframe_media',
+      'options',
+      'oe_media_iframe',
+    ]);
+    // Call the install hook of the Media module.
+    module_load_include('install', 'media');
+    media_install();
+  }
+
+  /**
+   * Test 'text with featured media' paragraph rendering.
+   */
+  public function testFeaturedMedia(): void {
+    $image_file = file_save_data(file_get_contents(drupal_get_path('module', 'oe_whitelabel_paragraphs') . '/tests/fixtures/example_1.jpeg'), 'public://example_1.jpeg');
+    $image_file->setPermanent();
+    $image_file->save();
+
+    $media_storage = $this->container->get('entity_type.manager')->getStorage('media');
+    $media = $media_storage->create([
+      'bundle' => 'image',
+      'name' => 'test image',
+      'oe_media_image' => [
+        'target_id' => $image_file->id(),
+        'alt' => 'Alt en',
+      ],
+    ]);
+    $media->save();
+
+    $paragraph_storage = $this->container->get('entity_type.manager')->getStorage('paragraph');
+    $paragraph = $paragraph_storage->create([
+      'type' => 'oe_text_feature_media',
+      'field_oe_title' => 'Media Title',
+      'field_oe_plain_text_long' => 'Media Caption',
+      'field_oe_media' => [
+        'target_id' => $media->id(),
+      ],
+    ]);
+    $paragraph->save();
+
+    // Testing: Image without wrapper.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(0, $crawler->filter('h3'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(1, $figure->filter('img.img-fluid'));
+    $this->assertCount(0, $figure->filter('iframe'));
+    $this->assertStringContainsString(
+      $image_file->getFilename(),
+      $figure->html()
+    );
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Testing: Image with wrapper aligned to left.
+    $paragraph->get('field_oe_text_long')->setValue('Media Full Text');
+    $paragraph->get('oe_paragraphs_variant')->setValue('left_featured');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(1, $crawler->filter('h3'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(1, $figure->filter('img.img-fluid'));
+    $this->assertCount(0, $figure->filter('iframe'));
+    $this->assertStringContainsString(
+      $image_file->getFilename(),
+      $figure->html()
+    );
+    $full_text = $crawler->filter('div.col-12.col-md-6.order-md-1');
+    $this->assertEquals('Media Full Text', trim($full_text->text()));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Testing: Image with wrapper aligned to right.
+    $paragraph->get('field_oe_text_long')->setValue('Media Full Text');
+    $paragraph->get('oe_paragraphs_variant')->setValue('right_featured');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(1, $crawler->filter('h3'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(1, $figure->filter('img.img-fluid'));
+    $this->assertCount(0, $figure->filter('iframe'));
+    $this->assertStringContainsString(
+      $image_file->getFilename(),
+      $figure->html()
+    );
+    $full_text = $crawler->filter('div.col-12.col-md-6.order-md-2');
+    $this->assertEquals('Media Full Text', trim($full_text->text()));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Create a remote video and add it to the paragraph.
+    $media = $media_storage->create([
+      'bundle' => 'remote_video',
+      'oe_media_oembed_video' => [
+        'value' => 'https://www.youtube.com/watch?v=1-g73ty9v04',
+      ],
+    ]);
+    $media->save();
+    $paragraph->set('field_oe_media', ['target_id' => $media->id()]);
+    $paragraph->save();
+
+    $paragraph_storage = $this->container->get('entity_type.manager')->getStorage('paragraph');
+    $paragraph = $paragraph_storage->create([
+      'type' => 'oe_text_feature_media',
+      'field_oe_title' => 'Media Title',
+      'field_oe_plain_text_long' => 'Media Caption',
+      'field_oe_media' => [
+        'target_id' => $media->id(),
+      ],
+    ]);
+    $paragraph->save();
+
+    // Testing: Iframe without wrapper.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(0, $crawler->filter('h3'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $this->assertCount(1, $crawler->filter('div.ratio.ratio-16x9'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(0, $figure->filter('img.img-fluid'));
+    $this->assertCount(1, $figure->filter('iframe'));
+    // Assert remote video is rendered properly.
+    $video_iframe = $crawler->filter('iframe');
+    $partial_iframe_url = Url::fromRoute('media.oembed_iframe', [], [
+      'query' => [
+        'url' => 'https://www.youtube.com/watch?v=1-g73ty9v04',
+      ],
+    ])->toString();
+    $this->assertStringContainsString($partial_iframe_url, $video_iframe->attr('src'));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Testing: Iframe with wrapper aligned to left.
+    $paragraph->get('field_oe_text_long')->setValue('Media Full Text');
+    $paragraph->get('oe_paragraphs_variant')->setValue('left_featured');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(1, $crawler->filter('h3'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $this->assertCount(1, $crawler->filter('div.ratio.ratio-16x9'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(0, $figure->filter('img.img-fluid'));
+    $this->assertCount(1, $figure->filter('iframe'));
+    // Assert remote video is rendered properly.
+    $video_iframe = $crawler->filter('iframe');
+    $partial_iframe_url = Url::fromRoute('media.oembed_iframe', [], [
+      'query' => [
+        'url' => 'https://www.youtube.com/watch?v=1-g73ty9v04',
+      ],
+    ])->toString();
+    $this->assertStringContainsString($partial_iframe_url, $video_iframe->attr('src'));
+    $full_text = $crawler->filter('div.col-12.col-md-6.order-md-1');
+    $this->assertEquals('Media Full Text', trim($full_text->text()));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Testing: Iframe with wrapper aligned to right.
+    $paragraph->get('field_oe_text_long')->setValue('Media Full Text');
+    $paragraph->get('oe_paragraphs_variant')->setValue('right_featured');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(1, $crawler->filter('h3'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $this->assertCount(1, $crawler->filter('div.ratio.ratio-16x9'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(0, $figure->filter('img.img-fluid'));
+    $this->assertCount(1, $figure->filter('iframe'));
+    // Assert remote video is rendered properly.
+    $video_iframe = $crawler->filter('iframe');
+    $partial_iframe_url = Url::fromRoute('media.oembed_iframe', [], [
+      'query' => [
+        'url' => 'https://www.youtube.com/watch?v=1-g73ty9v04',
+      ],
+    ])->toString();
+    $this->assertStringContainsString($partial_iframe_url, $video_iframe->attr('src'));
+    $full_text = $crawler->filter('div.col-12.col-md-6.order-md-2');
+    $this->assertEquals('Media Full Text', trim($full_text->text()));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Create an avportal video and add it to the paragraph.
+    $media = $media_storage->create([
+      'bundle' => 'av_portal_video',
+      'oe_media_avportal_video' => 'I-163162',
+    ]);
+    $media->save();
+    $paragraph->set('field_oe_media', ['target_id' => $media->id()]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $this->assertCount(1, $crawler->filter('h3'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-1'));
+    $this->assertCount(1, $crawler->filter('div.col-12.col-md-6.order-md-2'));
+    $this->assertCount(1, $crawler->filter('div.ratio.ratio-16x9'));
+    $figure = $crawler->filter('figure');
+    $this->assertCount(1, $figure);
+    $this->assertCount(0, $figure->filter('img.img-fluid'));
+    $this->assertCount(1, $figure->filter('iframe'));
+    // Assert remote video is rendered properly.
+    $video_iframe = $crawler->filter('iframe');
+    $this->assertStringContainsString('ec.europa.eu/avservices/play.cfm?ref=I-163162', $video_iframe->attr('src'));
+    $full_text = $crawler->filter('div.col-12.col-md-6.order-md-2');
+    $this->assertEquals('Media Full Text', trim($full_text->text()));
+    $this->assertEquals('Media Caption', trim($figure->filter('figcaption.bg-light.p-3')->text()));
+
+    // Testing: Link and media title.
+    $paragraph->get('field_oe_text_long')->setValue('Media Full Text');
+    $paragraph->get('oe_paragraphs_variant')->setValue('right_featured');
+    $paragraph->get('field_oe_feature_media_title')->setValue('Text title');
+    $paragraph->get('field_oe_link')->setValue([
+      'uri' => 'https://example1',
+      'title' => 'Example 1',
+    ]);
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('div.row'));
+    $this->assertCount(0, $crawler->filter('div.col-12.col-md-4'));
+    $media_title_text = $crawler->filter('h5.text-secondary');
+    $this->assertEquals('Text title', trim($media_title_text->text()));
+    $link = $crawler->filter('a[href="https://example1"]');
+    $this->assertCount(1, $link);
+    $this->assertEquals('Example 1', trim($link->text()));
+  }
+
+  /**
+   * Test 'banner' paragraph rendering.
+   */
+  public function testBanner(): void {
+    // Create English file.
+    $en_file = file_save_data(file_get_contents(drupal_get_path('module', 'oe_whitelabel_paragraphs') . '/tests/fixtures/example_1.jpeg'), 'public://example_1_en.jpeg');
+    $en_file->setPermanent();
+    $en_file->save();
+
+    // Create a media.
+    $media_storage = $this->container->get('entity_type.manager')->getStorage('media');
+    $media = $media_storage->create([
+      'bundle' => 'image',
+      'name' => 'test image en',
+      'oe_media_image' => [
+        'target_id' => $en_file->id(),
+        'alt' => 'Alt en',
+      ],
+    ]);
+    $media->save();
+
+    $paragraph_storage = $this->container->get('entity_type.manager')->getStorage('paragraph');
+    $paragraph = $paragraph_storage->create([
+      'type' => 'oe_banner',
+      'oe_paragraphs_variant' => 'oe_banner_image',
+      'field_oe_title' => 'Banner',
+      'field_oe_text' => 'Description',
+      'field_oe_link' => [
+        'uri' => 'http://www.example.com/',
+        'title' => 'Example',
+      ],
+      'field_oe_media' => [
+        'target_id' => $media->id(),
+      ],
+      'field_oe_banner_type' => 'hero_center',
+    ]);
+    $paragraph->save();
+
+    // Variant - image / Modifier - hero_center / Full width - No.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.overlay.text-center.hero'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image / Modifier - hero_left / Full width - No.
+    $paragraph->get('field_oe_banner_type')->setValue('hero_left');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(0, $crawler->filter('.bcl-banner.bg-lighter.text-dark.overlay.text-center.hero'));
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.overlay.hero'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image / Modifier - page_center / Full width - No.
+    $paragraph->get('field_oe_banner_type')->setValue('page_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.overlay.text-center'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image / Modifier - page_left / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('page_left');
+    $paragraph->get('field_oe_banner_full_width')->setValue('1');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.overlay.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image-shade / Modifier - hero_center / Full width - Yes.
+    $paragraph->get('oe_paragraphs_variant')->setValue('oe_banner_image_shade');
+    $paragraph->get('field_oe_banner_type')->setValue('hero_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.shade.text-center.hero.full-width'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image-shade / Modifier - hero_left / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('hero_left');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.shade.hero.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image-shade / Modifier - page_center / Full width - No.
+    $paragraph->get('field_oe_banner_type')->setValue('page_center');
+    $paragraph->get('field_oe_banner_full_width')->setValue('0');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.shade.text-center'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - image-shade / Modifier - page_left / Full width - No.
+    $paragraph->get('field_oe_banner_type')->setValue('page_left');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.shade'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . file_create_url($en_file->getFileUri()) . ')',
+      $image_element->attr('style')
+    );
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - default / Modifier - hero_center / Full width - No.
+    $paragraph->get('oe_paragraphs_variant')->setValue('default');
+    $paragraph->get('field_oe_banner_type')->setValue('hero_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.text-center.hero'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - default / Modifier - hero_left / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('hero_left');
+    $paragraph->get('field_oe_banner_full_width')->setValue('1');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.hero.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - default / Modifier - page_center / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('page_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.text-center.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - default / Modifier - page_left / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('page_left');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-lighter.text-dark.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - primary / Modifier - hero_center / Full width - Yes.
+    $paragraph->get('oe_paragraphs_variant')->setValue('oe_banner_primary');
+    $paragraph->get('field_oe_banner_type')->setValue('hero_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-primary.text-white.text-center.hero.full-width'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - primary / Modifier - hero_left / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('hero_left');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-primary.text-white.hero.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - primary / Modifier - page_center / Full width - Yes.
+    $paragraph->get('field_oe_banner_type')->setValue('page_center');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-primary.text-white.text-center.full-width'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(1, $crawler->filter('.bcl-banner.full-width'));
+
+    // Variant - primary / Modifier - page_left / Full width - No.
+    $paragraph->get('field_oe_banner_type')->setValue('page_left');
+    $paragraph->get('field_oe_banner_full_width')->setValue('0');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('.bcl-banner.bg-primary.text-white'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.hero'));
+    $this->assertCount(0, $crawler->filter('.bcl-banner.text-center'));
+
+    // No image should be displayed on 'default' variant.
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(0, $image_element);
+
+    $this->assertBannerRendering($crawler);
+    $this->assertCount(0, $crawler->filter('.bcl-banner.full-width'));
+
+    // Create a media using AV Portal image and add it to the paragraph.
+    $media = $media_storage->create([
+      'bundle' => 'av_portal_photo',
+      'oe_media_avportal_photo' => 'P-038924/00-15',
+      'uid' => 0,
+      'status' => 1,
+    ]);
+
+    $media->save();
+
+    $paragraph = $paragraph_storage->create([
+      'type' => 'oe_banner',
+      'oe_paragraphs_variant' => 'oe_banner_image',
+      'field_oe_text' => 'Description',
+      'field_oe_media' => [
+        'target_id' => $media->id(),
+      ],
+      'field_oe_banner_type' => 'hero_center',
+    ]);
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $image_element = $crawler->filter('.bcl-banner__image');
+    $this->assertCount(1, $image_element);
+    $this->assertStringContainsString(
+      'url(' . (file_create_url('avportal://P-038924/00-15.jpg')) . ')',
+      $image_element->attr('style')
+    );
+  }
+
+  /**
+   * Assert Banner is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertBannerRendering(Crawler $crawler): void {
+    $this->assertEquals('Banner', trim($crawler->filter('.bcl-banner__content div')->text()));
+    $this->assertEquals('Description', trim($crawler->filter('.bcl-banner__content p')->text()));
+    $this->assertCount(1, $crawler->filter('svg.bi.icon--fluid'));
+    $this->assertStringContainsString('Example', trim($crawler->filter('a.btn')->text()));
+    $this->assertStringContainsString('#chevron-right', trim($crawler->filter('a.btn')->html()));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ParagraphsTestBase.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ParagraphsTestBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..d40d2b5e1095f249844e7871a51526a7346b3961
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/ParagraphsTestBase.php
@@ -0,0 +1,97 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\ParagraphInterface;
+use Drupal\Tests\oe_whitelabel_paragraphs\Kernel\AbstractKernelTestBase;
+
+/**
+ * Base class for paragraphs tests.
+ */
+abstract class ParagraphsTestBase extends AbstractKernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'allowed_formats',
+    'datetime',
+    'description_list_field',
+    'entity_browser',
+    'entity_reference_revisions',
+    'field',
+    'file',
+    'file_link',
+    'filter',
+    'language',
+    'link',
+    'locale',
+    'media',
+    'media_avportal',
+    'media_avportal_mock',
+    'node',
+    'oe_media',
+    'oe_media_avportal',
+    'oe_media_iframe',
+    'oe_paragraphs',
+    'oe_paragraphs_banner',
+    'oe_paragraphs_description_list',
+    'oe_paragraphs_iframe_media',
+    'oe_paragraphs_media',
+    'oe_paragraphs_media_field_storage',
+    'oe_whitelabel_paragraphs',
+    'options',
+    'paragraphs',
+    'text',
+    'typed_link',
+    'user',
+    'views',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('paragraph');
+    $this->installEntitySchema('file');
+    $this->installSchema('file', ['file_usage']);
+    $this->installSchema('locale', [
+      'locales_location',
+      'locales_source',
+      'locales_target',
+    ]);
+    $this->installConfig([
+      'oe_paragraphs',
+      'oe_paragraphs_description_list',
+      'oe_whitelabel_paragraphs',
+      'filter',
+      'locale',
+      'language',
+      'node',
+    ]);
+  }
+
+  /**
+   * Render a paragraph.
+   *
+   * @param \Drupal\paragraphs\ParagraphInterface $paragraph
+   *   Paragraph entity.
+   *
+   * @return string
+   *   Rendered output.
+   *
+   * @throws \Exception
+   */
+  protected function renderParagraph(ParagraphInterface $paragraph): string {
+    $render = \Drupal::entityTypeManager()
+      ->getViewBuilder('paragraph')
+      ->view($paragraph, 'default');
+
+    return $this->renderRoot($render);
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/QuoteTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/QuoteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..21a0dee2f6f50bb87a106281ef49500933259827
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/QuoteTest.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\Entity\Paragraph;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the quote paragraphs.
+ */
+class QuoteTest extends ParagraphsTestBase {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    $paragraph = Paragraph::create([
+      'type' => 'oe_quote',
+      'field_oe_plain_text_long' => 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.',
+      'field_oe_text' => 'Cicero',
+    ]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertCount(1, $crawler->filter('figure.text-left'));
+    $quote = $crawler->filter('blockquote.blockquote');
+    $this->assertCount(1, $quote);
+    $this->assertEquals(
+      'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.',
+      trim($quote->text())
+    );
+    $caption = $crawler->filter('figcaption.blockquote-footer');
+    $this->assertEquals('Cicero', trim($caption->text()));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/RichTextTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/RichTextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..609a5bb08702ba6a5e04f611ec3345dff883696d
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/RichTextTest.php
@@ -0,0 +1,121 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\paragraphs\Entity\Paragraph;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the "Rich text" paragraphs.
+ */
+class RichTextTest extends ParagraphsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->filterFormat = FilterFormat::create([
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+      'weight' => 0,
+    ]);
+    $this->filterFormat->save();
+  }
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    $text_original = '<p id="paragraph-1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ornare et elit a dictum. Maecenas lacinia eros quis eros iaculis, sit amet bibendum massa facilisis. Integer arcu nisl, fringilla nec quam vel, tincidunt maximus ex. Suspendisse ac arcu efficitur, feugiat tellus vel, viverra sapien. Etiam vitae condimentum lorem. Nulla congue ligula lacinia efficitur tempus. Duis vitae auctor enim. Nulla iaculis, diam et sagittis scelerisque, est mauris luctus sem, a imperdiet lacus diam eu dui. Morbi accumsan, augue eu gravida elementum, libero mi blandit odio, eu fringilla nunc ipsum non tellus. Suspendisse dapibus elit at lobortis pretium. Quisque vestibulum ut purus sit amet molestie. Sed eget volutpat justo, vel varius augue. Vestibulum vel risus facilisis, feugiat sem aliquam, lobortis ante.</p><p id="paragraph-2"><strong>Bold</strong></p><p id="paragraph-3"><em>Italic</em></p><p id="paragraph-4"><a href="https://www.example-1.com">Link</a></p><p id="paragraph-5">List:</p><ul><li>option a</li><li">option b</li></ul><p id="paragraph-6">Numbered list:</p><ol><li>first option</li><li>second option</li></ol><p id="paragraph-7">Block quote:</p><blockquote><p>I am a block quote</p></blockquote>';
+    $paragraph = Paragraph::create([
+      'type' => 'oe_rich_text',
+      'field_oe_title' => 'Rich text example',
+      'field_oe_text_long' => [
+        'value' => $text_original,
+        'format' => 'filtered_html',
+      ],
+    ]);
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $title = $crawler->filter('h4');
+    $this->assertCount(1, $title);
+    $this->assertStringContainsString(
+      'Rich text example',
+      $title->html()
+    );
+    // Simple text.
+    $text = $crawler->filter('p#paragraph-1');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ornare et elit a dictum. Maecenas lacinia eros quis eros iaculis, sit amet bibendum massa facilisis. Integer arcu nisl, fringilla nec quam vel, tincidunt maximus ex. Suspendisse ac arcu efficitur, feugiat tellus vel, viverra sapien. Etiam vitae condimentum lorem. Nulla congue ligula lacinia efficitur tempus. Duis vitae auctor enim. Nulla iaculis, diam et sagittis scelerisque, est mauris luctus sem, a imperdiet lacus diam eu dui. Morbi accumsan, augue eu gravida elementum, libero mi blandit odio, eu fringilla nunc ipsum non tellus. Suspendisse dapibus elit at lobortis pretium. Quisque vestibulum ut purus sit amet molestie. Sed eget volutpat justo, vel varius augue. Vestibulum vel risus facilisis, feugiat sem aliquam, lobortis ante.',
+      $text->html()
+    );
+    // Bold format.
+    $text = $crawler->filter('p#paragraph-2 strong');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'Bold',
+      $text->html()
+    );
+    // Italic.
+    $text = $crawler->filter('p#paragraph-3 em');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'Italic',
+      $text->html()
+    );
+    // Link.
+    $text = $crawler->filter('p#paragraph-4 a');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'Link',
+      $text->html()
+    );
+    $this->assertStringContainsString(
+      'https://www.example-1.com',
+      $text->attr('href')
+    );
+    // Unordered list.
+    $text = $crawler->filter('ul li:nth-child(1)');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'option a',
+      $text->html()
+    );
+    $text = $crawler->filter('ul li:nth-child(2)');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'option b',
+      $text->html()
+    );
+    // Ordered list.
+    $text = $crawler->filter('ol li:nth-child(1)');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'first option',
+      $text->html()
+    );
+    $text = $crawler->filter('ol li:nth-child(2)');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'second option',
+      $text->html()
+    );
+    // Blcokquote.
+    $text = $crawler->filter('blockquote p');
+    $this->assertCount(1, $text);
+    $this->assertStringContainsString(
+      'I am a block quote',
+      $text->html()
+    );
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/SocialMediaFollowTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/SocialMediaFollowTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6834eafb575e70df09eec32c641f8dbe66977b6c
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/SocialMediaFollowTest.php
@@ -0,0 +1,90 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\oe_whitelabel_paragraphs\Kernel\PatternAssertions\LinksBlockAssertion;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the "Social media follow" paragraphs.
+ */
+class SocialMediaFollowTest extends LinksBlockAssertion {
+
+  /**
+   * Tests the rendering of the paragraph type.
+   */
+  public function testRendering(): void {
+    // Create social media follow paragraph with horizontal variant.
+    $paragraph = Paragraph::create([
+      'type' => 'oe_social_media_follow',
+      'field_oe_title' => 'Social media title',
+      'field_oe_social_media_variant' => 'horizontal',
+      'oe_w_links_block_background' => 'gray',
+      'field_oe_social_media_links' => $this->getSocialMediaLinks(),
+      'field_oe_social_media_see_more' => [
+        'title' => 'Other social networks',
+        'uri' => 'https://europa.eu/european-union/contact/social-networks_en',
+      ],
+    ]);
+    $paragraph->save();
+
+    // Testing: SocialMediaFollow horizontal gray.
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundGray($crawler);
+    $this->assertSocialMediaLinksBlockRendering($crawler);
+    $this->assertHorizontalLinks($crawler);
+
+    // Verify that links are rendered.
+    $this->assertSocialLinks($crawler);
+
+    // Testing: SocialMediaFollow vertical gray.
+    $paragraph->get('field_oe_social_media_variant')->setValue('vertical');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundGray($crawler);
+    $this->assertSocialMediaLinksBlockRendering($crawler);
+    $this->assertVerticalLinks($crawler);
+
+    // Verify that the paragraph contains all the links.
+    $this->assertSocialLinks($crawler);
+
+    // Testing: SocialMediaFollow horizontal transparent.
+    $paragraph->get('field_oe_social_media_variant')->setValue('horizontal');
+    $paragraph->get('oe_w_links_block_background')->setValue('transparent');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundTransparent($crawler);
+    $this->assertSocialMediaLinksBlockRendering($crawler);
+    $this->assertHorizontalLinks($crawler);
+
+    // Verify that the paragraph contains all the links.
+    $this->assertSocialLinks($crawler);
+
+    // Testing: SocialMediaFollow vertical transparent.
+    $paragraph->get('field_oe_social_media_variant')->setValue('vertical');
+    $paragraph->get('oe_w_links_block_background')->setValue('transparent');
+    $paragraph->save();
+
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    $this->assertBackgroundTransparent($crawler);
+    $this->assertSocialMediaLinksBlockRendering($crawler);
+    $this->assertVerticalLinks($crawler);
+
+    // Verify that the paragraph contains all the links.
+    $this->assertSocialLinks($crawler);
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/TimelineParagraphTest.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/TimelineParagraphTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..490a6598af0f4bb27012b121c132d6bd6d0dae31
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Paragraphs/TimelineParagraphTest.php
@@ -0,0 +1,157 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Paragraphs;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\paragraphs\Entity\Paragraph;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Tests the rendering for timeline paragraph type.
+ */
+class TimelineParagraphTest extends ParagraphsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'oe_paragraphs_timeline',
+    'oe_content_timeline_field',
+    'node',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installConfig([
+      'oe_paragraphs_timeline',
+      'oe_content_timeline_field',
+      'node',
+    ]);
+
+    // Remove the auto-paragraph and url-to-link filters from the plain text.
+    /** @var \Drupal\filter\Entity\FilterFormat $format */
+    $format = FilterFormat::load('plain_text');
+    $format->filters();
+    $format->removeFilter('filter_url');
+    $format->removeFilter('filter_autop');
+    $format->save();
+
+    FilterFormat::create([
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+      'filters' => [
+        'filter_html' => [
+          'status' => 1,
+          'settings' => [
+            'allowed_html' => '<strong>',
+          ],
+        ],
+      ],
+    ])->save();
+
+    FilterFormat::create([
+      'format' => 'full_html',
+      'name' => 'Full HTML',
+    ])->save();
+
+    $this->container->get('theme_installer')->install(['oe_whitelabel']);
+    $this->config('system.theme')->set('default', 'oe_whitelabel')->save();
+    $this->container->set('theme.registry', NULL);
+  }
+
+  /**
+   * Test 'timeline' paragraph rendering.
+   */
+  public function testTimeline(): void {
+    $paragraph = Paragraph::create([
+      'type' => 'oe_timeline',
+      'field_oe_timeline_expand' => '3',
+      'field_oe_timeline' => [
+        [
+          'label' => 'Label 1',
+          'title' => 'Title 1',
+          'body' => 'Description 1',
+        ],
+        [
+          'label' => 'Label 2',
+          'title' => 'Title 2',
+          'body' => '<p>Description 2</p>',
+        ],
+        [
+          'label' => 'Label 3',
+          'title' => 'Title 3',
+          'body' => '<p>Description <strong>3</strong></p>',
+          'format' => 'plain_text',
+        ],
+        [
+          'label' => 'Label 4',
+          'title' => 'Title 4',
+          'body' => '<p>Description <strong>4</strong></p>',
+          'format' => 'filtered_html',
+        ],
+        [
+          'label' => 'Label 5',
+          'title' => 'Title 5',
+          'body' => '<p>Description <strong>5</strong></p>',
+          'format' => 'full_html',
+        ],
+        [
+          'label' => 'Label 6',
+          'title' => 'Title 6',
+          'body' => 'Description 6',
+        ],
+      ],
+    ]);
+
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    // No heading should be rendered if the paragraph has no heading set.
+    $this->assertCount(0, $crawler->filter('h2.ecl-u-type-heading-2'));
+    $this->assertCount(1, $crawler->filter('ol.bcl-timeline'));
+    $this->assertCount(7, $crawler->filter('ol.bcl-timeline li'));
+    $this->assertCount(1, $crawler->filter('ol.bcl-timeline li .label-collapsed'));
+    $this->assertCount(1, $crawler->filter('ol.bcl-timeline li.bcl-timeline__item--toggle'));
+    $this->assertEquals('Label 1', trim($crawler->filter('ol.bcl-timeline li:nth-child(1) h5')->html()));
+    $this->assertEquals('Title 1', trim($crawler->filter('ol.bcl-timeline li:nth-child(1) h6')->html()));
+    $this->assertEquals('Description 1', trim($crawler->filter('ol.bcl-timeline li:nth-child(1) div')->html()));
+    $this->assertEquals('Label 2', trim($crawler->filter('ol.bcl-timeline li:nth-child(2) h5')->html()));
+    $this->assertEquals('Title 2', trim($crawler->filter('ol.bcl-timeline li:nth-child(2) h6')->html()));
+    // Explicit format "plain_text" specified.
+    $this->assertEquals('&lt;p&gt;Description 2&lt;/p&gt;', trim($crawler->filter('ol.bcl-timeline li:nth-child(2) div')->html()));
+    $this->assertEquals('Label 3', trim($crawler->filter('ol.bcl-timeline li:nth-child(3) h5')->html()));
+    $this->assertEquals('Title 3', trim($crawler->filter('ol.bcl-timeline li:nth-child(3) h6')->html()));
+    $this->assertEquals('&lt;p&gt;Description &lt;strong&gt;3&lt;/strong&gt;&lt;/p&gt;', trim($crawler->filter('ol.bcl-timeline li:nth-child(3) div')->html()));
+    $this->assertEquals('Label 4', trim($crawler->filter('ol.bcl-timeline li:nth-child(4) h5')->html()));
+    $this->assertEquals('Title 4', trim($crawler->filter('ol.bcl-timeline li:nth-child(4) h6')->html()));
+    // Explicit format "filtered_html" specified.
+    $this->assertEquals('Description <strong>4</strong>', trim($crawler->filter('ol.bcl-timeline li:nth-child(4) div')->html()));
+    $this->assertEquals('<p>Description <strong>5</strong></p>', trim($crawler->filter('ol.bcl-timeline li:nth-child(5) div')->html()));
+    $this->assertEquals('Label 5', trim($crawler->filter('ol.bcl-timeline li:nth-child(5) h5')->html()));
+    $this->assertEquals('Title 5', trim($crawler->filter('ol.bcl-timeline li:nth-child(5) h6')->html()));
+    $this->assertEquals('Label 6', trim($crawler->filter('ol.bcl-timeline li:nth-child(6) h5')->html()));
+    $this->assertEquals('Title 6', trim($crawler->filter('ol.bcl-timeline li:nth-child(6) h6')->html()));
+    // Explicit format "full_html" specified.
+    $this->assertEquals('Description 6', trim($crawler->filter('ol.bcl-timeline li:nth-child(6) div')->html()));
+    $this->assertEquals('Show more 3 items', trim($crawler->filter('button .label-collapsed')->text()));
+
+    // Increase limit to print all the items and set timeline heading.
+    $paragraph->set('field_oe_timeline_expand', '7');
+    $paragraph->save();
+    $html = $this->renderParagraph($paragraph);
+    $crawler = new Crawler($html);
+
+    // Assert rendering is updated.
+    $this->assertCount(6, $crawler->filter('ol.bcl-timeline li'));
+    $this->assertCount(0, $crawler->filter('ol.bcl-timeline label-collapsed'));
+    $this->assertCount(0, $crawler->filter('ol.bcl-timeline li.bcl-timeline__item--toggle'));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/LinksBlockAssertion.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/LinksBlockAssertion.php
new file mode 100644
index 0000000000000000000000000000000000000000..dfde169bb942304683a9dd47c85795ec857dd7fe
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/LinksBlockAssertion.php
@@ -0,0 +1,223 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\PatternAssertions;
+
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Class for asserting links block paragraphs.
+ */
+class LinksBlockAssertion {
+
+  /**
+   * Returns a list of link items for Social media follow paragraph.
+   *
+   * @return array
+   *   An array of link items.
+   */
+  protected function getSocialMediaLinks(): array {
+    return [
+      [
+        'title' => 'Email',
+        'uri' => 'mailto:example@com',
+        'link_type' => 'email',
+      ],
+      [
+        'title' => 'Facebook',
+        'uri' => 'https://facebook.com',
+        'link_type' => 'facebook',
+      ],
+      [
+        'title' => 'Flickr',
+        'uri' => 'https://www.flickr.com',
+        'link_type' => 'flickr',
+      ],
+      [
+        'title' => 'Google+',
+        'uri' => 'https://google.com',
+        'link_type' => 'google',
+      ],
+      [
+        'title' => 'Instagram',
+        'uri' => 'https://instagram.com',
+        'link_type' => 'instagram',
+      ],
+      [
+        'title' => 'LinkedIn',
+        'uri' => 'https://linkedin.com',
+        'link_type' => 'linkedin',
+      ],
+      [
+        'title' => 'Pinterest',
+        'uri' => 'https://pinterest.com',
+        'link_type' => 'pinterest',
+      ],
+      [
+        'title' => 'RSS',
+        'uri' => 'https://rss-example.com',
+        'link_type' => 'rss',
+      ],
+      [
+        'title' => 'Storify',
+        'uri' => 'https://storify.com',
+        'link_type' => 'storify',
+      ],
+      [
+        'title' => '1st Twitter',
+        'uri' => 'https://twitter.com',
+        'link_type' => 'twitter',
+      ],
+      [
+        'title' => '2nd Twitter',
+        'uri' => 'https://twitter.com',
+        'link_type' => 'twitter',
+      ],
+      [
+        'title' => 'Yammer',
+        'uri' => 'https://yammer.com',
+        'link_type' => 'yammer',
+      ],
+      [
+        'title' => 'Youtube',
+        'uri' => 'https://youtube.com',
+        'link_type' => 'youtube',
+      ],
+      [
+        'title' => 'Vimeo',
+        'uri' => 'https://vimeo.com',
+        'link_type' => 'vimeo',
+      ],
+    ];
+  }
+
+  /**
+   * Returns a list of link items for Block Links paragraph.
+   *
+   * @return array
+   *   An array of link items.
+   */
+  protected function getBlockLinks(): array {
+    return [
+      [
+        'title' => 'European Commission',
+        'uri' => 'https://example.com',
+      ],
+      [
+        'title' => 'Priorities',
+        'uri' => 'https://example.com',
+      ],
+      [
+        'title' => 'Jobs, Growth and Investment',
+        'uri' => 'https://example.com',
+      ],
+    ];
+  }
+
+  /**
+   * Assert links from social media.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertSocialLinks(Crawler $crawler): void {
+    $links = $crawler->filter('ul');
+    $links_html = $links->html();
+    $this->assertStringContainsString('Email', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 5) = \'#email\']'));
+    $this->assertStringContainsString('Facebook', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 8) = \'#facebook\']'));
+    $this->assertStringContainsString('Flickr', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 6) = \'#flickr\']'));
+    $this->assertStringContainsString('Google+', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 6) = \'#google\']'));
+    $this->assertStringContainsString('Instagram', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 9) = \'#instagram\']'));
+    $this->assertStringContainsString('LinkedIn', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 8) = \'#linkedin\']'));
+    $this->assertStringContainsString('Pinterest', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 9) = \'#pinterest\']'));
+    $this->assertStringContainsString('RSS', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 3) = \'#rss\']'));
+    $this->assertStringContainsString('Storify', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 7) = \'#storify\']'));
+    $this->assertStringContainsString('1st Twitter', $links_html);
+    $this->assertStringContainsString('2nd Twitter', $links_html);
+    $this->assertCount(2, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 7) = \'#twitter\']'));
+    $this->assertStringContainsString('Yammer', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 6) = \'#yammer\']'));
+    $this->assertStringContainsString('Youtube', $links_html);
+    $this->assertCount(1, $crawler->filterXPath('//*[name()=\'use\' and substring(@*, string-length(@*) - 7) = \'#youtube\']'));
+    $this->assertStringContainsString('Other social networks', $links_html);
+  }
+
+  /**
+   * Assert Background is gray.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertBackgroundGray(Crawler $crawler): void {
+    $this->assertCount(1, $crawler->filter('div.bg-light.px-4.py-3'));
+  }
+
+  /**
+   * Assert Background is transparent.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertBackgroundTransparent(Crawler $crawler): void {
+    $this->assertCount(0, $crawler->filter('div.bg-light.px-4.py-3'));
+  }
+
+  /**
+   * Assert Links Block with Social Media is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertSocialMediaLinksBlockRendering(Crawler $crawler): void {
+    $this->assertCount(1, $crawler->filter('h5.fw-bold.pb-3.mb-3.border-bottom'));
+    $this->assertCount(1, $crawler->filter('ul.ps-0.mb-0'));
+    $this->assertCount(15, $crawler->filter('li.list-unstyled'));
+    $this->assertCount(14, $crawler->filter('li.list-unstyled.me-4-5'));
+  }
+
+  /**
+   * Assert direction is horizontal.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   * @param bool $social
+   *   Flag to determine if is block links with social media or not.
+   */
+  protected function assertHorizontalLinks(Crawler $crawler, $social = TRUE): void {
+    $this->assertCount($social ? 15 : 3, $crawler->filter('li.d-inline'));
+  }
+
+  /**
+   * Assert direction is vertical.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertVerticalLinks(Crawler $crawler): void {
+    $this->assertCount(0, $crawler->filter('li.d-inline'));
+  }
+
+  /**
+   * Assert Links Block is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   */
+  protected function assertLinksBlockRendering(Crawler $crawler): void {
+    $this->assertCount(1, $crawler->filter('h5.fw-bold.pb-3.mb-3.border-bottom'));
+    $this->assertCount(1, $crawler->filter('ul.ps-0.mb-0'));
+    $this->assertCount(3, $crawler->filter('li.list-unstyled'));
+    $this->assertCount(2, $crawler->filter('li.list-unstyled.me-4-5'));
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/ListingAssertion.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/ListingAssertion.php
new file mode 100644
index 0000000000000000000000000000000000000000..f032eb90a05f6f61b793fd97b477b28c7ee90232
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/PatternAssertions/ListingAssertion.php
@@ -0,0 +1,99 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\PatternAssertions;
+
+use Drupal\file\Entity\File;
+use PHPUnit\Framework\Assert;
+use Symfony\Component\DomCrawler\Crawler;
+
+/**
+ * Class for asserting Listing pattern.
+ */
+class ListingAssertion extends Assert {
+
+  /**
+   * Assert default variant of Listing is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   * @param \Drupal\file\Entity\File $file
+   *
+   *   Image file added to the list item.
+   */
+  public function assertDefaultListingRendering(Crawler $crawler, File $file): void {
+    $this->assertCount(6, $crawler->filter('div.listing-item.border-bottom.border-md-0.border-0.card'));
+    $this->assertCount(6, $crawler->filter('div.mw-listing-img'));
+    $this->assertCount(6, $crawler->filter('div.card-body.p-0.pb-md-0.pb-3'));
+    $text_element = $crawler->filter('div.card-text');
+    $this->assertCount(6, $text_element);
+    $this->assertImageRendering($crawler, $file);
+  }
+
+  /**
+   * Assert highlight variant of Listing is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   * @param \Drupal\file\Entity\File $file
+   *   Image file added to the list item.
+   */
+  public function assertHighlightListingRendering(Crawler $crawler, File $file): void {
+    $this->assertCount(6, $crawler->filter('div.listing-item--highlight.border-0.bg-lighter.card'));
+    $text_element = $crawler->filter('div.card-text');
+    $this->assertCount(6, $text_element);
+    $this->assertImageRendering($crawler, $file);
+  }
+
+  /**
+   * Assert Listing is rendering correctly.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   * @param int $nid
+   *   Node identifier.
+   */
+  public function assertListingRendering(Crawler $crawler, int $nid): void {
+    $this->assertCount(1, $crawler->filter('div.bcl-listing'));
+    $this->assertCount(6, $crawler->filter('div.row-cols-1.g-4 > div.col'));
+    $this->assertStringContainsString('Listing item block title', trim($crawler->filter('h2.fw-bold')->text()));
+    $this->assertCount(6, $crawler->filter('h5.card-title'));
+    $link_element = $crawler->filter('a.text-underline-hover');
+    $this->assertCount(6, $link_element);
+    $this->assertStringContainsString(
+      'node/' . $nid,
+      $link_element->attr('href')
+    );
+    $text_element = $crawler->filter('div.card-text');
+    $this->assertStringContainsString('Item title 1', trim($crawler->filter('h5.card-title > a.text-underline-hover')->text()));
+    $this->assertStringContainsString('Label 1 - 1', trim($crawler->filter('span.badge')->eq(0)->text()));
+    $this->assertStringContainsString('Label 2 - 1', trim($crawler->filter('span.badge')->eq(1)->text()));
+    $this->assertStringContainsString(
+      'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ut ex tristique, dignissim sem ac, bibendum est.',
+      $text_element->text()
+    );
+  }
+
+  /**
+   * Assert image is rendering.
+   *
+   * @param \Symfony\Component\DomCrawler\Crawler $crawler
+   *   The DomCrawler where to check the element.
+   * @param \Drupal\file\Entity\File $file
+   *   Image file added to the card.
+   */
+  public function assertImageRendering(Crawler $crawler, File $file): void {
+    $image_element = $crawler->filter('.card-img-top');
+    $this->assertCount(6, $image_element);
+    $this->assertStringContainsString(
+      file_url_transform_relative(file_create_url($file->getFileUri())),
+      $image_element->attr('src')
+    );
+    $this->assertStringContainsString(
+      'Alt for image 1',
+      $image_element->attr('alt')
+    );
+  }
+
+}
diff --git a/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Traits/RenderTrait.php b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Traits/RenderTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7864898de26ee3cbc4a23d4b9206dd35ba9fd3a
--- /dev/null
+++ b/modules/oe_whitelabel_paragraphs/tests/src/Kernel/Traits/RenderTrait.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\Tests\oe_whitelabel_paragraphs\Kernel\Traits;
+
+/**
+ * Helper rendering trait.
+ */
+trait RenderTrait {
+
+  /**
+   * Renders final HTML given a structured array tree.
+   *
+   * @param array $elements
+   *   The structured array describing the data to be rendered.
+   *
+   * @return string
+   *   The rendered HTML.
+   *
+   * @throws \Exception
+   *   When called from inside another renderRoot() call.
+   *
+   * @see \Drupal\Core\Render\RendererInterface::render()
+   */
+  protected function renderRoot(array &$elements): string {
+    return (string) $this->container->get('renderer')->renderRoot($elements);
+  }
+
+}
diff --git a/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.module b/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.module
index 4f9d92b6559b21f80b33f061ac41e55ce509f8dd..7e9200f5314102e096c50e995ddde05edc83f904 100755
--- a/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.module
+++ b/modules/oe_whitelabel_starter_event/oe_whitelabel_starter_event.module
@@ -78,10 +78,6 @@ function _oe_whitelabel_starter_event_preprocess_featured_media(array &$variable
   $thumbnail = $media->get('thumbnail')->first();
   $variables['image'] = ImageValueObject::fromImageItem($thumbnail);
 
-  if ($variables['view_mode'] == 'teaser') {
-    $variables['image'] = ['#markup' => $variables['image']->getSource()];
-  }
-
   $cacheability->applyTo($variables);
 }
 
diff --git a/modules/oe_whitelabel_starter_event/templates/node--oe-sc-event--teaser.html.twig b/modules/oe_whitelabel_starter_event/templates/node--oe-sc-event--teaser.html.twig
index bc004c43f5327330e664393a675f1679f8044939..8f5f2799bf8a1e2d92750c4e94fbd6bd6b27655e 100755
--- a/modules/oe_whitelabel_starter_event/templates/node--oe-sc-event--teaser.html.twig
+++ b/modules/oe_whitelabel_starter_event/templates/node--oe-sc-event--teaser.html.twig
@@ -7,17 +7,19 @@
 {% set _title %}
   <a class="standalone" href="{{ url }}">{{ label }}</a>
 {% endset %}
-{% set _content %}
-  <span class="text-muted text-nowrap me-4-5">{{ content.oe_sc_event_dates }}</span>
-{% endset %}
 {% block content %}
 <article{{attributes}}>
   {{ pattern('card', {
     variant: 'search',
     title: _title,
     text: content.oe_summary,
-    image: image,
-    content: _content
+    image: image ? {
+      path: image.src,
+      alt: image.alt,
+    },
+    meta: [
+      content.oe_sc_event_dates|field_value,
+    ],
   }) }}
 </article>
 {% endblock %}
diff --git a/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.module b/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.module
index 78143f0865ff2bebd8b193fb633267e8761e102d..4af48a40b9d87a1dc3269fef15d1d20cc0ee5963 100644
--- a/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.module
+++ b/modules/oe_whitelabel_starter_news/oe_whitelabel_starter_news.module
@@ -68,9 +68,5 @@ function oe_whitelabel_starter_news_preprocess_node__oe_sc_news(&$variables) {
   $thumbnail = $media->get('thumbnail')->first();
   $variables['image'] = ImageValueObject::fromImageItem($thumbnail);
 
-  if ($variables['view_mode'] == 'teaser') {
-    $variables['image'] = ['#markup' => $variables['image']->getSource()];
-  }
-
   $cacheability->applyTo($variables);
 }
diff --git a/modules/oe_whitelabel_starter_news/templates/node--oe-sc-news--teaser.html.twig b/modules/oe_whitelabel_starter_news/templates/node--oe-sc-news--teaser.html.twig
index 6650bbca5f729368d42e1bd09696fe7bfd03cf19..4d5474929e67b1dd9530df32cc7fe29b1f0f5e9e 100644
--- a/modules/oe_whitelabel_starter_news/templates/node--oe-sc-news--teaser.html.twig
+++ b/modules/oe_whitelabel_starter_news/templates/node--oe-sc-news--teaser.html.twig
@@ -7,17 +7,19 @@
 {% set _title %}
   <a class="standalone" href="{{ url }}">{{ label }}</a>
 {% endset %}
-{% set _content %}
-  <span class="text-muted text-nowrap me-4-5">{{ content.oe_publication_date }}</span>
-{% endset %}
 {% block content %}
 <article{{attributes}}>
   {{ pattern('card', {
     variant: 'search',
     title: _title,
     text: content.oe_summary,
-    image: image,
-    content: _content
+    image: image ? {
+      path: image.src,
+      alt: image.alt,
+    },
+    meta: [
+      content.oe_publication_date|field_value
+    ],
   }) }}
 </article>
 {% endblock %}
diff --git a/oe_whitelabel.theme b/oe_whitelabel.theme
index 3da1f38601b763077e2430d595823bb79a5cf0e3..6be05efd19aac9b9da2c23fe12627f36130b6e1b 100644
--- a/oe_whitelabel.theme
+++ b/oe_whitelabel.theme
@@ -9,7 +9,16 @@ declare(strict_types = 1);
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
-use Drupal\oe_whitelabel_helper\EuropeanUnionLanguages;
+use Drupal\oe_bootstrap_theme_helper\EuropeanUnionLanguages;
+use Drupal\oe_whitelabel\DocumentMediaWrapper;
+
+// Include all files from the includes directory.
+$includes_path = __DIR__ . '/includes/*.inc';
+foreach (glob($includes_path) as $filename) {
+  // The inspection disallowing basename() is not relevant for known paths.
+  // phpcs:ignore QualityAssurance.Functions.DrupalWrappers.FoundWithAlternative
+  require_once __DIR__ . '/includes/' . basename($filename);
+}
 
 /**
  * Implements hook_form_FORM_ID_alter() for facets_forms.
@@ -129,3 +138,33 @@ function oe_whitelabel_preprocess_page(&$variables) {
   }
   $variables['site_logo_href'] = $site_logo_href;
 }
+
+/**
+ * Implements hook_preprocess_HOOK() for document media bundle.
+ */
+function oe_whitelabel_preprocess_media__document__default(&$variables) {
+  /** @var \Drupal\media\Entity\Media $media */
+  $media = $variables['media'];
+
+  $wrapper = new DocumentMediaWrapper($media);
+  if ($wrapper->isEmpty()) {
+    return;
+  }
+
+  $variables['file'] = $wrapper->toFileValueObject();
+
+  // Generate the file information for all available translations.
+  foreach ($media->getTranslationLanguages() as $langcode => $language) {
+    // We don't want to include the information of the current language again.
+    if ($media->language()->getId() === $langcode) {
+      continue;
+    }
+
+    $translation = $media->getTranslation($langcode);
+    $wrapper = new DocumentMediaWrapper($translation);
+    if ($wrapper->isEmpty()) {
+      continue;
+    }
+    $variables['translations'][] = $wrapper->toFileValueObject();
+  }
+}
diff --git a/runner.yml.dist b/runner.yml.dist
index 5dead5f252406e08da76d6bf45b5609756365058..738915c5460f8217fd42ce10d158a44520e7c3ee 100644
--- a/runner.yml.dist
+++ b/runner.yml.dist
@@ -26,6 +26,7 @@ drupal:
     - "./vendor/bin/drush en oe_whitelabel_search -y"
     - "./vendor/bin/drush en oe_whitelabel_starter_news -y"
     - "./vendor/bin/drush en oe_whitelabel_starter_event -y"
+    - "./vendor/bin/drush en oe_whitelabel_paragraphs -y"
     - "./vendor/bin/drush en toolbar -y"
     - "./vendor/bin/drush theme:enable oe_whitelabel -y"
     - "./vendor/bin/drush theme:enable seven -y"
@@ -41,6 +42,7 @@ drupal:
         - "bower_components"
         - "vendor"
         - "${drupal.root}"
+      file_private_path: 'sites/default/files/private'
     databases:
       sparql_default:
         default:
diff --git a/src/DocumentMediaWrapper.php b/src/DocumentMediaWrapper.php
new file mode 100644
index 0000000000000000000000000000000000000000..b486b3b8d5b40ec10d6535d4bd37e797623a732f
--- /dev/null
+++ b/src/DocumentMediaWrapper.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\oe_whitelabel;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\media\MediaInterface;
+use Drupal\oe_bootstrap_theme\ValueObject\FileValueObject;
+
+/**
+ * Wraps a media entity of bundle "document".
+ *
+ * @internal
+ */
+class DocumentMediaWrapper {
+
+  /**
+   * The media.
+   *
+   * @var \Drupal\media\MediaInterface
+   */
+  protected MediaInterface $media;
+
+  /**
+   * Construct a new wrapper object.
+   *
+   * @param \Drupal\media\MediaInterface $media
+   *   The media to wrap.
+   */
+  public function __construct(MediaInterface $media) {
+    if ($media->bundle() !== 'document') {
+      throw new \InvalidArgumentException(sprintf('Invalid media of type "%s" passed, "document" expected.', $media->bundle()));
+    }
+
+    $this->media = $media;
+  }
+
+  /**
+   * Returns if the media is empty.
+   *
+   * A media is considered empty if the current active field, based on the type,
+   * is empty.
+   *
+   * @return bool
+   *   Whether the media is referencing a field or not.
+   */
+  public function isEmpty(): bool {
+    $field = $this->getActiveField();
+    return !$field || $field->isEmpty();
+  }
+
+  /**
+   * Returns the type of the media.
+   *
+   * @return string|null
+   *   The media type, usually "remote" or "local". NULL if no value set.
+   */
+  public function getType(): ?string {
+    return $this->media->get('oe_media_file_type')->value;
+  }
+
+  /**
+   * Creates a file value object from the current media values.
+   *
+   * @return \Drupal\oe_bootstrap_theme\ValueObject\FileValueObject|null
+   *   A file value object, or NULL if the media is empty.
+   */
+  public function toFileValueObject(): ?FileValueObject {
+    if ($this->isEmpty()) {
+      return NULL;
+    }
+
+    $field = $this->getActiveField();
+    $object = $this->getType() === 'remote'
+      ? FileValueObject::fromFileLink($field->first())
+      : FileValueObject::fromFileEntity($field->first()->entity);
+
+    return $object->setTitle($this->media->getName())
+      ->setLanguageCode($this->media->language()->getId());
+  }
+
+  /**
+   * Returns the field that is being used for the document, based on the type.
+   *
+   * @return \Drupal\Core\Field\FieldItemListInterface|null
+   *   The field item list, or NULL if an invalid type is specified.
+   */
+  protected function getActiveField(): ?FieldItemListInterface {
+    if (!$this->getType()) {
+      return NULL;
+    }
+
+    switch ($this->getType()) {
+      case 'remote':
+        return $this->media->get('oe_media_remote_file');
+
+      case 'local':
+        return $this->media->get('oe_media_file');
+
+      default:
+        return NULL;
+    }
+  }
+
+}
diff --git a/templates/content/node--oe-project--teaser.html.twig b/templates/content/node--oe-project--teaser.html.twig
index 8c8b78986fae297575d62792e1ffea8660043a39..f01553e0069326592353239ad208c99328ab9ddf 100644
--- a/templates/content/node--oe-project--teaser.html.twig
+++ b/templates/content/node--oe-project--teaser.html.twig
@@ -7,18 +7,27 @@
 {% set _title %}
   <a class="standalone" href="{{ url }}">{{ label }}</a>
 {% endset %}
-{% set _content %}
-  <span class="text-muted text-nowrap me-4-5">{{ content.oe_project_dates }}</span>
-{% endset %}
+{% set _badges = [] %}
+{% for _item in content.oe_subject|field_value %}
+  {% set _badges = _badges|merge([{
+    label: _item,
+  }]) %}
+{% endfor %}
 {% block content %}
 <article{{attributes}}>
   {{ pattern('card', {
     variant: 'search',
     title: _title,
-    text: content.oe_teaser,
-    image: image,
+    text: content.oe_teaser|field_value,
+    image: {
+      path: image.src,
+      alt: image.alt,
+    },
+    meta: [
+      content.oe_project_dates|field_value,
+    ],
     content: _content,
-    badges: badges,
+    badges: _badges,
   }) }}
 </article>
 {% endblock %}
diff --git a/templates/media/media--document--default.html.twig b/templates/media/media--document--default.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..dcaaf033af0fc12effb79e1d307adc2823f436ba
--- /dev/null
+++ b/templates/media/media--document--default.html.twig
@@ -0,0 +1,14 @@
+{#
+/**
+ * @file
+ * Theme override to display a media item.
+ *
+ * @see ./core/themes/stable/templates/content/media.html.twig
+ */
+#}
+{% if file %}
+  {{ pattern('file', {
+    file: file,
+    translations: translations,
+  }) }}
+{% endif %}
diff --git a/templates/overrides/field/field--entity-reference-revisions--paragraph.html.twig b/templates/overrides/field/field--entity-reference-revisions--paragraph.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e8157acd91f75c38a8ac289d6de36e387760d0c0
--- /dev/null
+++ b/templates/overrides/field/field--entity-reference-revisions--paragraph.html.twig
@@ -0,0 +1,13 @@
+{#
+/**
+ * @file
+ * Theme override for the entity reference revisions field which allowed to use paragraphs.
+ *
+ * @see ./templates/field/field--bare.html.twig
+ */
+#}
+{% for item in items %}
+  <div class="my-4">
+    {{ item.content }}
+  </div>
+{% endfor %}
diff --git a/templates/paragraphs/paragraph--oe-accordion.html.twig b/templates/paragraphs/paragraph--oe-accordion.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..4f84608b0bb2a2d810ab3f530fae42acedc470f6
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-accordion.html.twig
@@ -0,0 +1,11 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'accordion' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('accordion', {
+  'items': items,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-banner.html.twig b/templates/paragraphs/paragraph--oe-banner.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..cbe34141aea9caf1a37c41d0812937cd60e6b54e
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-banner.html.twig
@@ -0,0 +1,41 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'banner' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{% set attributes = create_attribute() %}
+{% if url %}
+  {% set _call_to_action = {
+    'label': label,
+    'path': url,
+    'attributes': create_attribute({
+      'class': [
+        'btn',
+        variant == 'primary' ? 'btn-light' : 'btn-primary',
+      ],
+    }),
+    'icon': {
+      'name': 'chevron-right',
+      'size': 'fluid',
+      'path': bcl_icon_path,
+    },
+  } %}
+{% endif %}
+{% set _hero = 'hero' in pattern %}
+{% set _shade = 'shade' in variant %}
+{{ pattern('banner', {
+  'variant': variant,
+  'title': content.field_oe_title,
+  'description':  content.field_oe_text,
+  'call_to_action': _call_to_action,
+  'image': image.src,
+  'hero': _hero,
+  'shade': _shade,
+  'full_width': full_width,
+  'centered': 'center' in alignment,
+  'attributes': attributes,
+}) }}
+
diff --git a/templates/paragraphs/paragraph--oe-content-row--variant-inpage-navigation.html.twig b/templates/paragraphs/paragraph--oe-content-row--variant-inpage-navigation.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..42899b15b81c15db40d340974160616a424d8546
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-content-row--variant-inpage-navigation.html.twig
@@ -0,0 +1,15 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'Content row' #type and 'Inpage navigation' #variant paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('inpage_navigation', {
+  'title': title,
+  'links': links,
+  'content': content.field_oe_paragraphs,
+  'full_layout': true,
+  'attributes': attributes,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-content-row.html.twig b/templates/paragraphs/paragraph--oe-content-row.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..385a7771806fab78d395a1a4dc870c827902d210
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-content-row.html.twig
@@ -0,0 +1,13 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'content row' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+<div class="row">
+  <div class="col-md-12">
+    {{ content.field_oe_paragraphs }}
+  </div>
+</div>
diff --git a/templates/paragraphs/paragraph--oe-description-list.html.twig b/templates/paragraphs/paragraph--oe-description-list.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..a78c5d6e4fdb5aa33b7c19fb0e75022ab2ebb7bb
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-description-list.html.twig
@@ -0,0 +1,17 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'Description list' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+
+{% if title is not empty %}
+  <h4 class="fw-bold mb-4">{{ title }}</h4>
+{% endif %}
+
+{{ pattern('description_list', {
+  'items': items,
+  'orientation': orientation,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-facts-figures.html.twig b/templates/paragraphs/paragraph--oe-facts-figures.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..31ede665604ea586e47ed521e721e1b2fe0b04bc
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-facts-figures.html.twig
@@ -0,0 +1,14 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'Facts and Figures' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('fact_figures', {
+  'title': title|default(''),
+  'items': items,
+  'columns': columns,
+  'link': link_more,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-links-block.html.twig b/templates/paragraphs/paragraph--oe-links-block.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..36eee1905965f5128c006672c0871930439b81cd
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-links-block.html.twig
@@ -0,0 +1,14 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'links block' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('links_block', {
+  'orientation': orientation,
+  'background': background,
+  'title': title,
+  'links': links,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-list-item-block.html.twig b/templates/paragraphs/paragraph--oe-list-item-block.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..22c1a716cd588d2b841aaed68f63e07022756f08
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-list-item-block.html.twig
@@ -0,0 +1,16 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'List item block' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('listing', {
+  'variant': variant,
+  'columns': columns,
+  'items': items,
+  'link': link,
+  'title': title,
+}) }}
+
diff --git a/templates/paragraphs/paragraph--oe-quote.html.twig b/templates/paragraphs/paragraph--oe-quote.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..a01bbbe7d273ad7da6b2af071070751173cc4a90
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-quote.html.twig
@@ -0,0 +1,12 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'quote' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('blockquote', {
+    'quote': content.field_oe_plain_text_long,
+    'attribution': content.field_oe_text,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-rich-text.html.twig b/templates/paragraphs/paragraph--oe-rich-text.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..8024655618529752a8a8f7b5c77c4af940ce6248
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-rich-text.html.twig
@@ -0,0 +1,10 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'rich text' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+<h4 class="fw-bold mb-4">{{ content.field_oe_title }}</h4>
+{{ content|without('field_oe_title') }}
diff --git a/templates/paragraphs/paragraph--oe-social-media-follow.html.twig b/templates/paragraphs/paragraph--oe-social-media-follow.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..36eee1905965f5128c006672c0871930439b81cd
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-social-media-follow.html.twig
@@ -0,0 +1,14 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'links block' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{ pattern('links_block', {
+  'orientation': orientation,
+  'background': background,
+  'title': title,
+  'links': links,
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-text-feature-media.html.twig b/templates/paragraphs/paragraph--oe-text-feature-media.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..ff2a4d42828b4913429b128e930a98533ee6c22d
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-text-feature-media.html.twig
@@ -0,0 +1,25 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'featured_media' type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+
+{% if not paragraph.field_oe_link.isEmpty %}
+  {# Add cache info from the Link field to the page. #}
+  {% set bubble_cache = content.field_oe_link|render %}
+{% endif %}
+
+{{ pattern('featured_media', {
+  'embedded_media': embedded_media,
+  'image': image,
+  'ratio': ratio,
+  'text_position': text_position,
+  'title': not paragraph.field_oe_title.isEmpty ? content.field_oe_title,
+  'subtitle': not paragraph.field_oe_feature_media_title.isEmpty ? content.field_oe_feature_media_title,
+  'caption': not paragraph.field_oe_plain_text_long.isEmpty ? content.field_oe_plain_text_long,
+  'text': not paragraph.field_oe_text_long.isEmpty ? content.field_oe_text_long,
+  'link': link|default([]),
+}) }}
diff --git a/templates/paragraphs/paragraph--oe-timeline--default.html.twig b/templates/paragraphs/paragraph--oe-timeline--default.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..813ac0dd257882e9c17c431a5fc00efce76beafe
--- /dev/null
+++ b/templates/paragraphs/paragraph--oe-timeline--default.html.twig
@@ -0,0 +1,14 @@
+{#
+/**
+ * @file
+ * Theme override to display the 'timeline' #type paragraph.
+ *
+ * @see ./modules/contrib/paragraphs/templates/paragraph.html.twig
+ */
+#}
+{{
+  pattern('timeline', {
+    hide_from: hide_from,
+    items: content.items,
+  })
+}}
diff --git a/tests/src/Functional/ContentNewsRenderTest.php b/tests/src/Functional/ContentNewsRenderTest.php
index e7d42ad30fe26ad94b2bf1ad3666868b7ec210e1..34497412920ce01de6679277aee8982525af6fb4 100644
--- a/tests/src/Functional/ContentNewsRenderTest.php
+++ b/tests/src/Functional/ContentNewsRenderTest.php
@@ -145,12 +145,12 @@ class ContentNewsRenderTest extends WhitelabelBrowserTestBase {
     // Assert content banner content.
     $this->assertEquals(
       'http://www.example.org is a web page',
-      trim($crawler->filter('p.card-text')->text())
+      trim($crawler->filter('div.card-text')->text())
     );
     // Assert content banner publication date.
     $this->assertEquals(
       '09 February 2022',
-      trim($crawler->filter('div.card-body > span.text-muted')->text())
+      trim($crawler->filter('div.card-body > div > span.text-muted')->text())
     );
   }
 
diff --git a/tests/src/Kernel/ProjectRenderTest.php b/tests/src/Kernel/ProjectRenderTest.php
index ca3ab1cc07bba1446c578c2e6571c9ee2a583c57..17d06e3b93750c356f43fd6df6fd261abba86d3b 100644
--- a/tests/src/Kernel/ProjectRenderTest.php
+++ b/tests/src/Kernel/ProjectRenderTest.php
@@ -28,6 +28,7 @@ class ProjectRenderTest extends ContentRenderTestBase {
     'oe_content_extra_project',
     'oe_whitelabel_extra_project',
     'system',
+    'twig_field_value',
     'user',
   ];
 
@@ -95,7 +96,6 @@ class ProjectRenderTest extends ContentRenderTestBase {
 
     $assert = new CardAssert();
 
-    // @todo Once the OEL-1159 issue is resolved, then add text to alt.
     $expected_values = [
       'title' => 'Project 1',
       'url' => '/node/1',
@@ -103,7 +103,7 @@ class ProjectRenderTest extends ContentRenderTestBase {
       'badges' => ['EU financing'],
       'image' => [
         'src' => 'example_1.jpeg',
-        'alt' => '',
+        'alt' => 'Alternative text',
       ],
       'content' => [
         '10 May 2020',