From cc9a6a0f50f575d2b20e6588617fc0856c519be0 Mon Sep 17 00:00:00 2001
From: Brian Weaver <weaver.299@osu.edu>
Date: Tue, 25 Feb 2020 11:25:56 -0500
Subject: [PATCH] Update paragraphs module to 1.11

---
 composer.json                                 |   7 +-
 composer.lock                                 |  34 ++-
 vendor/composer/installed.json                |  31 ++-
 web/modules/paragraphs/PATCHES.txt            |   7 +
 web/modules/paragraphs/README.txt             |  16 +-
 web/modules/paragraphs/composer.json          |   6 +-
 .../config/schema/paragraphs_type.schema.yml  |  15 +-
 web/modules/paragraphs/css/_summary.scss      |  77 ++++--
 web/modules/paragraphs/css/_variables.scss    |   4 +
 .../paragraphs/css/paragraphs.dragdrop.css    |   8 -
 .../paragraphs/css/paragraphs.dragdrop.scss   |   7 +-
 .../paragraphs/css/paragraphs.formatter.css   |  58 +++--
 .../paragraphs/css/paragraphs.modal.css       |   3 +
 .../paragraphs/css/paragraphs.modal.scss      |   3 +
 .../paragraphs/css/paragraphs.widget.css      | 163 ++++++++----
 .../paragraphs/css/paragraphs.widget.scss     | 103 ++++++--
 web/modules/paragraphs/icons/icon-view.svg    |   6 +-
 .../paragraphs/js/paragraphs.actions.js       |   9 +-
 .../js/paragraphs.add_above_button.js         |  39 +--
 web/modules/paragraphs/js/paragraphs.admin.js | 111 ++++++--
 .../paragraphs/js/paragraphs.dragdrop.js      |  24 +-
 web/modules/paragraphs/js/paragraphs.modal.js |  87 ++++---
 .../paragraphs.paragraphs_type.text_image.yml |   2 +-
 .../paragraphs_demo/paragraphs_demo.info.yml  |   9 +-
 .../paragraphs_demo/paragraphs_demo.install   |   6 +-
 .../src/Functional}/ParagraphsDemoTest.php    |  17 +-
 .../views.view.paragraphs_library_browser.yml |   1 +
 .../paragraphs_library.info.yml               |   9 +-
 .../paragraphs_library.install                |  39 ++-
 .../paragraphs_library.module                 |  17 +-
 .../src/Controller/LibraryItemController.php  |   3 +-
 .../src/Entity/LibraryItem.php                |  28 +-
 .../src/Form/LibraryItemForm.php              |  42 +--
 .../Form/LibraryItemRevisionDeleteForm.php    |   6 +-
 .../Form/LibraryItemRevisionRevertForm.php    |   6 +-
 .../src/LibraryItemAccessControlHandler.php   |   7 -
 ...lowedParagraphsTypeConstraintValidator.php |  32 +--
 .../Functional}/MultilingualBehaviorTest.php  |  32 +--
 .../Functional/ParagraphsLibraryItemTest.php  |  57 +++-
 .../ParagraphsLibraryItemTranslationTest.php  |  39 ++-
 .../src/Functional/ParagraphsLibraryTest.php} |  78 +++---
 .../ParagraphsContentModerationTest.php       |  25 +-
 ...ParagraphsLibraryItemEntityBrowserTest.php |  96 ++++++-
 .../paragraphs_type_permissions.info.yml      |   9 +-
 .../src/ParagraphsTypePermissions.php         |   2 -
 .../ParagraphsTypePermissionsTest.php         |  38 ++-
 web/modules/paragraphs/paragraphs.info.yml    |  11 +-
 web/modules/paragraphs/paragraphs.install     | 210 ++++++++++++++-
 .../paragraphs/paragraphs.libraries.yml       |  23 +-
 web/modules/paragraphs/paragraphs.module      |  68 ++++-
 .../paragraphs/paragraphs.post_update.php     | 153 ++++++++++-
 .../paragraphs/paragraphs.services.yml        |   5 +
 .../paragraphs/src/Entity/Paragraph.php       | 246 ++++++++++--------
 .../paragraphs/src/Entity/ParagraphsType.php  | 148 +++++++++--
 .../src/Feeds/Target/Paragraphs.php           |   2 +-
 .../src/Form/ParagraphsTypeDeleteConfirm.php  |   2 +-
 .../src/Form/ParagraphsTypeForm.php           |  23 +-
 .../paragraphs/src/ParagraphInterface.php     |  20 +-
 .../paragraphs/src/ParagraphStorageSchema.php |   5 +-
 .../paragraphs/src/ParagraphsBehaviorBase.php |   8 +-
 .../src/ParagraphsBehaviorInterface.php       |   5 +-
 .../src/ParagraphsServiceProvider.php         |   2 +-
 .../ParagraphsTypeAccessControlHandler.php    |  34 +++
 .../src/ParagraphsTypeIconUuidLookup.php      |  55 ++++
 .../src/ParagraphsTypeInterface.php           |   7 +
 .../ParagraphSelection.php                    |  57 +---
 .../ParagraphsSummaryFormatter.php            |   7 +-
 .../FieldWidget/InlineParagraphsWidget.php    |  70 ++---
 .../Field/FieldWidget/ParagraphsWidget.php    | 137 +++++++---
 .../Plugin/migrate/field/FieldCollection.php  |  40 ---
 .../src/Plugin/migrate/field/Paragraphs.php   |  52 ----
 .../migrate/process/ProcessPluginBase.php     |  11 +-
 .../Plugin/migrate/source/DrupalSqlBase.php   |  10 +-
 .../migrate/source/d7/FieldCollectionItem.php |   4 +-
 .../migrate/source/d7/FieldableEntity.php     |  10 +-
 .../migrate/source/d7/ParagraphsItem.php      |   2 +-
 .../src/Tests/Classic/ParagraphsTestBase.php  |   7 +-
 .../ParagraphsExperimentalTestBase.php        |   5 +-
 .../templates/paragraphs-summary.html.twig    |  45 ++++
 .../paragraphs_test/paragraphs_test.info.yml  |  11 +-
 .../Behavior/TestBoldTextBehavior.php         |   7 +-
 .../Behavior/TestTextColorBehavior.php        |   7 +-
 .../Classic/ParagraphsAccessTest.php          |  27 +-
 .../Classic/ParagraphsAddModesTest.php        |   9 +-
 .../Classic/ParagraphsAdministrationTest.php  | 104 +++-----
 ...assicContentModerationTranslationsTest.php |  13 +-
 .../Classic/ParagraphsConfigTest.php          |   6 +-
 .../Classic/ParagraphsContactTest.php         |   6 +-
 .../Classic/ParagraphsEditModesTest.php       |  36 ++-
 ...anslationWithNonTranslatableParagraphs.php |   2 +-
 .../Classic/ParagraphsFieldGroupTest.php      |   5 +-
 .../ParagraphsInlineEntityFormTest.php        |  11 +-
 .../Classic/ParagraphsPreviewTest.php         |  16 +-
 .../ParagraphsSummaryFormatterTest.php        |  10 +-
 .../Functional/Classic/ParagraphsTestBase.php | 208 +++++++++++++++
 .../Classic/ParagraphsTranslationTest.php     |  44 ++--
 .../Classic/ParagraphsTypesTest.php           |  50 +++-
 .../Functional}/Classic/ParagraphsUiTest.php  |   9 +-
 .../Classic/ParagraphsWidgetButtonsTest.php   |  32 +--
 .../ParagraphsExperimentalAccessTest.php      |  65 ++++-
 .../ParagraphsExperimentalAddModesTest.php    |  11 +-
 ...ragraphsExperimentalAdministrationTest.php |  99 +++----
 .../ParagraphsExperimentalAlterByTypeTest.php |   2 +-
 .../ParagraphsExperimentalBehaviorsTest.php   |  47 ++--
 .../ParagraphsExperimentalConfigTest.php      |   4 +-
 .../ParagraphsExperimentalContactTest.php     |   6 +-
 ...entalContentModerationTranslationsTest.php |  13 +-
 ...agraphsExperimentalDragAndDropModeTest.php |  28 +-
 ...graphsExperimentalDuplicateFeatureTest.php |  24 +-
 .../ParagraphsExperimentalEditModesTest.php   | 105 +++++---
 ...anslationWithNonTranslatableParagraphs.php |   2 +-
 .../ParagraphsExperimentalFieldGroupTest.php  |   5 +-
 ...aragraphsExperimentalHeaderActionsTest.php |  46 ++--
 ...graphsExperimentalInlineEntityFormTest.php |  11 +-
 .../ParagraphsExperimentalPreviewTest.php     |  17 +-
 ...agraphsExperimentalReplicateEnableTest.php |   2 +-
 ...graphsExperimentalSummaryFormatterTest.php |  10 +-
 .../ParagraphsExperimentalTestBase.php        |  47 ++++
 .../ParagraphsExperimentalTranslationTest.php |  56 ++--
 ...ParagraphsExperimentalTranslationsTest.php |  39 ++-
 .../ParagraphsExperimentalTypesTest.php       |   9 +-
 .../ParagraphsExperimentalUiTest.php          |  15 +-
 ...aragraphsExperimentalWidgetButtonsTest.php |  32 ++-
 .../ParagraphsExperimentalBehaviorsTest.php   |   9 +-
 .../ParagraphsExperimentalUiTest.php          |  31 ++-
 ...aragraphsExperimentalWidgetButtonsTest.php |  47 +++-
 .../Functional}/ParagraphsUninstallTest.php   |  19 +-
 .../ParagraphsExperimentalAddWidgetTest.php   |  89 +++++--
 ...raphsExperimentalClientsideButtonsTest.php |  38 ++-
 ...aphsExperimentalEditPerspectivesUiTest.php | 136 ++++++----
 ...ragraphsExperimentalWidgetElementsTest.php |  13 +-
 .../ParagraphsTestBaseTrait.php               |   4 +-
 .../tests/src/Kernel/ParagraphsAccessTest.php |   2 +-
 .../Kernel/ParagraphsBehaviorPluginsTest.php  |  37 ++-
 .../Kernel/ParagraphsCollapsedSummaryTest.php |  45 +++-
 .../ParagraphsCompositeRelationshipTest.php   |   1 -
 .../Kernel/ParagraphsEntityMethodsTest.php    | 117 +++++++++
 .../src/Kernel/ParagraphsIsChangedTest.php    |   5 -
 .../src/Kernel/ParagraphsReplicateTest.php    |   2 -
 .../ParagraphsCoreVersionUiTestTrait.php      |  58 +++++
 140 files changed, 3309 insertions(+), 1554 deletions(-)
 create mode 100644 web/modules/paragraphs/PATCHES.txt
 rename web/modules/paragraphs/modules/paragraphs_demo/{src/Tests => tests/src/Functional}/ParagraphsDemoTest.php (94%)
 rename web/modules/paragraphs/modules/paragraphs_library/{src/Tests => tests/src/Functional}/MultilingualBehaviorTest.php (88%)
 rename web/modules/paragraphs/modules/paragraphs_library/{src/Tests/ParagraphsLibraryItemTest.php => tests/src/Functional/ParagraphsLibraryTest.php} (88%)
 rename web/modules/paragraphs/modules/paragraphs_type_permissions/{src/Tests => tests/src/Functional}/ParagraphsTypePermissionsTest.php (86%)
 create mode 100644 web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php
 create mode 100644 web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
 create mode 100644 web/modules/paragraphs/templates/paragraphs-summary.html.twig
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAccessTest.php (90%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAddModesTest.php (97%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsAdministrationTest.php (84%)
 rename web/modules/paragraphs/tests/src/Functional/{ => Classic}/ParagraphsClassicContentModerationTranslationsTest.php (98%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsConfigTest.php (97%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsContactTest.php (85%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsEditModesTest.php (67%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php (98%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsFieldGroupTest.php (90%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsInlineEntityFormTest.php (92%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsPreviewTest.php (87%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsSummaryFormatterTest.php (88%)
 create mode 100644 web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsTranslationTest.php (96%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsTypesTest.php (72%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsUiTest.php (94%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Classic/ParagraphsWidgetButtonsTest.php (78%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAccessTest.php (80%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAddModesTest.php (97%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAdministrationTest.php (84%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalAlterByTypeTest.php (95%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalBehaviorsTest.php (86%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalConfigTest.php (98%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalContactTest.php (87%)
 rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalContentModerationTranslationsTest.php (98%)
 rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalDragAndDropModeTest.php (98%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php (88%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalEditModesTest.php (62%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php (98%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalFieldGroupTest.php (90%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalHeaderActionsTest.php (87%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalInlineEntityFormTest.php (92%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalPreviewTest.php (86%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalReplicateEnableTest.php (79%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalSummaryFormatterTest.php (88%)
 create mode 100644 web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalTranslationTest.php (95%)
 rename web/modules/paragraphs/tests/src/Functional/{ => Experimental}/ParagraphsExperimentalTranslationsTest.php (77%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalTypesTest.php (92%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalUiTest.php (90%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/Experimental/ParagraphsExperimentalWidgetButtonsTest.php (89%)
 rename web/modules/paragraphs/{src/Tests => tests/src/Functional}/ParagraphsUninstallTest.php (76%)
 create mode 100644 web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
 create mode 100644 web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php

diff --git a/composer.json b/composer.json
index d1ef7f2961..8de26d8ad5 100644
--- a/composer.json
+++ b/composer.json
@@ -149,7 +149,7 @@
         "drupal/mobile_device_detection": "^3.2",
         "drupal/module_filter": "^3.1",
         "drupal/pantheon_advanced_page_cache": "^1.0",
-        "drupal/paragraphs": "1.6",
+        "drupal/paragraphs": "^1.6",
         "drupal/pathauto": "^1.0",
         "drupal/realname": "^1.0@RC",
         "drupal/rebuild_cache_access": "^1.4",
@@ -302,6 +302,9 @@
             },
             "drupal/entity_clone": {
                 "3060223": "https://www.drupal.org/files/issues/2019-10-17/%20entity_clone-corrupted-paragraph-cloning-3060223-5.patch"
+            },
+            "drupal/paragraphs": {
+                "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch"
             }
         }
     },
@@ -313,4 +316,4 @@
             "php": "7.0.8"
         }
     }
-}
+}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
index 90dc22db4e..e304ef53bb 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "926e92273c27be3e90bbd5a0458f014a",
+    "content-hash": "9cebdfa2dca9a89bb18005ed1f9db499",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -3590,7 +3590,8 @@
                 },
                 "patches_applied": {
                     "2799049": "patches/role_based_email_access-2799049-d87.patch",
-                    "2949017": "https://www.drupal.org/files/issues/2018-09-19/allow-uid-1-to-delete-2949017-36-3.patch"
+                    "2862291": "https://www.drupal.org/files/issues/2019-07-02/2862291-21.patch",
+                    "2949017": "https://www.drupal.org/files/issues/2019-12-12/2949017-59.patch"
                 }
             },
             "autoload": {
@@ -6273,29 +6274,29 @@
         },
         {
             "name": "drupal/paragraphs",
-            "version": "1.6.0",
+            "version": "1.11.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/paragraphs.git",
-                "reference": "8.x-1.6"
+                "reference": "8.x-1.11"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.6.zip",
-                "reference": "8.x-1.6",
-                "shasum": "cd93e244f3a78dabdcf362adc31e59aad25b3fae"
+                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.11.zip",
+                "reference": "8.x-1.11",
+                "shasum": "4fa849a249fbc689ca0c83523a967c08767e91af"
             },
             "require": {
-                "drupal/core": "~8",
+                "drupal/core": "^8.7.7 || ^9",
                 "drupal/entity_reference_revisions": "~1.3"
             },
             "require-dev": {
                 "drupal/block_field": "~1.0",
                 "drupal/ctools": "3.x-dev",
                 "drupal/diff": "~1.0",
-                "drupal/entity_browser": "1.x-dev",
+                "drupal/entity_browser": "2.x-dev",
                 "drupal/entity_usage": "2.x-dev",
-                "drupal/field_group": "~1.0",
+                "drupal/field_group": "3.x-dev",
                 "drupal/inline_entity_form": "~1.0",
                 "drupal/paragraphs-paragraphs_library": "*",
                 "drupal/replicate": "~1.0",
@@ -6311,12 +6312,15 @@
                     "dev-1.x": "1.x-dev"
                 },
                 "drupal": {
-                    "version": "8.x-1.6",
-                    "datestamp": "1550692525",
+                    "version": "8.x-1.11",
+                    "datestamp": "1581850829",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
                     }
+                },
+                "patches_applied": {
+                    "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch"
                 }
             },
             "notification-url": "https://packages.drupal.org/8/downloads",
@@ -6340,6 +6344,10 @@
                     "name": "jeroen.b",
                     "homepage": "https://www.drupal.org/user/1853532"
                 },
+                {
+                    "name": "jstoller",
+                    "homepage": "https://www.drupal.org/user/99012"
+                },
                 {
                     "name": "miro_dietiker",
                     "homepage": "https://www.drupal.org/user/227761"
@@ -6348,7 +6356,7 @@
             "description": "Enables the creation of Paragraphs entities.",
             "homepage": "https://www.drupal.org/project/paragraphs",
             "support": {
-                "source": "http://cgit.drupalcode.org/paragraphs"
+                "source": "https://git.drupalcode.org/project/paragraphs"
             }
         },
         {
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 037d9c35b1..899a4506a1 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -6470,30 +6470,30 @@
     },
     {
         "name": "drupal/paragraphs",
-        "version": "1.6.0",
-        "version_normalized": "1.6.0.0",
+        "version": "1.11.0",
+        "version_normalized": "1.11.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/paragraphs.git",
-            "reference": "8.x-1.6"
+            "reference": "8.x-1.11"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.6.zip",
-            "reference": "8.x-1.6",
-            "shasum": "cd93e244f3a78dabdcf362adc31e59aad25b3fae"
+            "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.11.zip",
+            "reference": "8.x-1.11",
+            "shasum": "4fa849a249fbc689ca0c83523a967c08767e91af"
         },
         "require": {
-            "drupal/core": "~8",
+            "drupal/core": "^8.7.7 || ^9",
             "drupal/entity_reference_revisions": "~1.3"
         },
         "require-dev": {
             "drupal/block_field": "~1.0",
             "drupal/ctools": "3.x-dev",
             "drupal/diff": "~1.0",
-            "drupal/entity_browser": "1.x-dev",
+            "drupal/entity_browser": "2.x-dev",
             "drupal/entity_usage": "2.x-dev",
-            "drupal/field_group": "~1.0",
+            "drupal/field_group": "3.x-dev",
             "drupal/inline_entity_form": "~1.0",
             "drupal/paragraphs-paragraphs_library": "*",
             "drupal/replicate": "~1.0",
@@ -6509,12 +6509,15 @@
                 "dev-1.x": "1.x-dev"
             },
             "drupal": {
-                "version": "8.x-1.6",
-                "datestamp": "1550692525",
+                "version": "8.x-1.11",
+                "datestamp": "1581850829",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
                 }
+            },
+            "patches_applied": {
+                "3114512": "https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch"
             }
         },
         "installation-source": "dist",
@@ -6539,6 +6542,10 @@
                 "name": "jeroen.b",
                 "homepage": "https://www.drupal.org/user/1853532"
             },
+            {
+                "name": "jstoller",
+                "homepage": "https://www.drupal.org/user/99012"
+            },
             {
                 "name": "miro_dietiker",
                 "homepage": "https://www.drupal.org/user/227761"
@@ -6547,7 +6554,7 @@
         "description": "Enables the creation of Paragraphs entities.",
         "homepage": "https://www.drupal.org/project/paragraphs",
         "support": {
-            "source": "http://cgit.drupalcode.org/paragraphs"
+            "source": "https://git.drupalcode.org/project/paragraphs"
         }
     },
     {
diff --git a/web/modules/paragraphs/PATCHES.txt b/web/modules/paragraphs/PATCHES.txt
new file mode 100644
index 0000000000..3dda710f53
--- /dev/null
+++ b/web/modules/paragraphs/PATCHES.txt
@@ -0,0 +1,7 @@
+This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)
+Patches applied to this directory:
+
+3114512
+Source: https://www.drupal.org/files/issues/2020-02-20/3114512-1.patch
+
+
diff --git a/web/modules/paragraphs/README.txt b/web/modules/paragraphs/README.txt
index ecc17371ec..f1c652a6b9 100644
--- a/web/modules/paragraphs/README.txt
+++ b/web/modules/paragraphs/README.txt
@@ -36,13 +36,17 @@ and move paragraphs including their children around and into other paragraphs.
 During drag & drop mode, paragraphs are also displayed as a summary only, which
 results in a very compact display that makes it easier to move them around.
 
-To use this, an additional library is necessary, which needs to be put in the
-/libraries folder. Download from https://github.com/RubaXa/Sortable/releases,
-make sure that the folder name is Sortable (with uppercase S) so that the path
-to the javascript file is /libraries/Sortable/Sortable.min.js.
+Starting with Drupal 8.8.0, the necessary library is part of Drupal core and
+this feature is always available.
 
-Due to a known issue (https://github.com/RubaXa/Sortable/pull/1154), version
-1.6.0 should be used with the patch from that pull request.
+In Drupal 8.7 and earlier, an additional library is necessary, which needs to be
+put in the libraries folder. Download from
+https://github.com/RubaXa/Sortable/releases, make sure that the folder name is
+Sortable (with uppercase S) so that the path to the javascript file is
+/libraries/Sortable/Sortable.min.js.
+
+Use the version 1.10+ as it's tested and approved. Older versions may introduce
+bugs with nested drag & drop functionality.
 
 If the file exists, the feature will automatically be available.
 
diff --git a/web/modules/paragraphs/composer.json b/web/modules/paragraphs/composer.json
index 158e9f5183..7d4960b265 100644
--- a/web/modules/paragraphs/composer.json
+++ b/web/modules/paragraphs/composer.json
@@ -4,7 +4,7 @@
   "type": "drupal-module",
   "license": "GPL-2.0",
   "require": {
-    "drupal/core": "~8",
+    "drupal/core": "^8.7.7 || ^9",
     "drupal/entity_reference_revisions": "~1.3"
   },
   "suggest": {
@@ -14,10 +14,10 @@
     "drupal/diff": "~1.0",
     "drupal/replicate": "~1.0",
     "drupal/inline_entity_form": "~1.0",
-    "drupal/field_group": "~1.0",
+    "drupal/field_group": "3.x-dev",
     "drupal/block_field": "~1.0",
     "drupal/ctools": "3.x-dev",
-    "drupal/entity_browser": "1.x-dev",
+    "drupal/entity_browser": "2.x-dev",
     "drupal/entity_usage": "2.x-dev",
     "drupal/search_api": "~1.0"
   }
diff --git a/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml b/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml
index a04120dd99..15fc2f1dab 100644
--- a/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml
+++ b/web/modules/paragraphs/config/schema/paragraphs_type.schema.yml
@@ -11,6 +11,9 @@ paragraphs.paragraphs_type.*:
     icon_uuid:
       type: string
       label: 'Icon uuid'
+    icon_default:
+      type: string
+      label: 'Default icon'
     description:
       type: text
       label: 'Description'
@@ -53,9 +56,9 @@ entity_reference_selection.default:paragraph:
     edit_mode:
       type: string
     title:
-      type: string
+      type: label
     title_plural:
-      type: string
+      type: label
     default_paragraph_type:
       type: string
 
@@ -63,9 +66,9 @@ field.widget.settings.entity_reference_paragraphs:
   type: mapping
   mapping:
     title:
-      type: string
+      type: label
     title_plural:
-      type: string
+      type: label
     edit_mode:
       type: string
     add_mode:
@@ -79,9 +82,9 @@ field.widget.settings.paragraphs:
   type: mapping
   mapping:
     title:
-      type: string
+      type: label
     title_plural:
-      type: string
+      type: label
     edit_mode:
       type: string
     closed_mode:
diff --git a/web/modules/paragraphs/css/_summary.scss b/web/modules/paragraphs/css/_summary.scss
index b08472f07f..5c646f4cad 100644
--- a/web/modules/paragraphs/css/_summary.scss
+++ b/web/modules/paragraphs/css/_summary.scss
@@ -18,6 +18,7 @@
     text-align: center;
     white-space: nowrap;
     vertical-align: baseline;
+    margin: 3px 0;
 
     // Empty badges collapse automatically
     &:empty {
@@ -26,33 +27,63 @@
   }
 }
 
-.paragraph-info {
-  display: flex;
-  // Needed not just because of centering but also to prevent span child to
-  // stretch vertically.
-  align-items: center;
-}
-
 // We are using .js prefix here mainly because we want to apply this style rules
 // only for JS version of the element.
 .js {
-  .paragraphs-collapsed-description {
-    position: relative;
-    height: 1.538em;
-    overflow: hidden;
-    color: #777;
-    word-break: break-all;
-    line-height: 1.538em;
-
-    // Fade out text element.
-    &::after {
+  .paragraphs-description {
+    .paragraphs-content-wrapper,
+    .paragraphs-plugin-wrapper {
+      position: relative;
+      height: 1.538em;
+      overflow: hidden;
+      word-break: break-all;
+      line-height: 1.538em;
+      text-overflow: ellipsis;
+    }
+
+    .summary-plugin-label::after {
+      content: ": ";
+    }
+
+    .summary-content {
+      color: $content-summary-color;
+    }
+
+    .summary-plugin {
+      display: inline-block;
+      padding-right: 5px;
+      font-size: 0.7rem;
+      color: $behavior-summary-color;
+
+      &:not(:last-child) {
+        border-right: 2px solid $light-grey;
+      }
+
+      &:not(:first-child) {
+        padding: 0 5px;
+      }
+    }
+  }
+
+  // Behavior tab is active.
+  .behavior-active {
+    // Hide plugin summary.
+    .paragraphs-expanded-description .paragraphs-plugin-wrapper,
+    .paragraphs-content {
+      display: none;
+    }
+
+    // Display paragraphs behavior.
+    .paragraphs-behavior {
       display: block;
-      position: absolute;
-      top: 0;
-      right: 0;
-      width: 3em;
-      background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%);
-      content: "\00a0";
+    }
+  }
+
+  // Content tab is active.
+  .content-active {
+    // Hide content summary.
+    .paragraphs-expanded-description .paragraphs-content-wrapper {
+      display: none;
     }
   }
 }
diff --git a/web/modules/paragraphs/css/_variables.scss b/web/modules/paragraphs/css/_variables.scss
index 47660ad360..3ed4ce6265 100644
--- a/web/modules/paragraphs/css/_variables.scss
+++ b/web/modules/paragraphs/css/_variables.scss
@@ -1,6 +1,7 @@
 // Colours.
 
 $grey-dark: #999999 !default;
+$light-grey: #e5e3de !default;
 
 
 // Layout.
@@ -35,3 +36,6 @@ $info-icon-size: 16px !default;
 $badge-padding-y: .15em !default;
 $badge-padding-x: .3em !default;
 $badge-color: #787878 !default;
+$content-summary-color: #666666 !default;
+$behavior-summary-color: #888888 !default;
+$paragraph-hover-bg: #f7fcff !default;
diff --git a/web/modules/paragraphs/css/paragraphs.dragdrop.css b/web/modules/paragraphs/css/paragraphs.dragdrop.css
index e743f211e5..a8abdc811d 100644
--- a/web/modules/paragraphs/css/paragraphs.dragdrop.css
+++ b/web/modules/paragraphs/css/paragraphs.dragdrop.css
@@ -176,14 +176,6 @@
   line-height: 1.538em;
 }
 
-.paragraphs-dragdrop__item .paragraphs-summary-wrapper > .paragraphs-collapsed-description {
-  -webkit-box-flex: 1;
-  -webkit-flex-grow: 1;
-      -ms-flex-positive: 1;
-          flex-grow: 1;
-  font-style: italic;
-}
-
 .paragraphs-dragdrop__handle {
   display: -webkit-box;
   display: -webkit-flex;
diff --git a/web/modules/paragraphs/css/paragraphs.dragdrop.scss b/web/modules/paragraphs/css/paragraphs.dragdrop.scss
index 09cd3f7bec..a451bbd69c 100644
--- a/web/modules/paragraphs/css/paragraphs.dragdrop.scss
+++ b/web/modules/paragraphs/css/paragraphs.dragdrop.scss
@@ -171,18 +171,13 @@
     width: calc(100% - var(--dnd-icon-size));
   }
 
-  // Collapsed summary container.
+  // Closed summary container.
   .paragraphs-summary-wrapper {
     display: flex;
     align-items: center;
     height: 1.538em;
     margin: 5px 0;
     line-height: 1.538em;
-
-    > .paragraphs-collapsed-description {
-      flex-grow: 1;
-      font-style: italic;
-    }
   }
 }
 
diff --git a/web/modules/paragraphs/css/paragraphs.formatter.css b/web/modules/paragraphs/css/paragraphs.formatter.css
index af9d1a8366..47f6580171 100644
--- a/web/modules/paragraphs/css/paragraphs.formatter.css
+++ b/web/modules/paragraphs/css/paragraphs.formatter.css
@@ -10,41 +10,57 @@
   text-align: center;
   white-space: nowrap;
   vertical-align: baseline;
+  margin: 3px 0;
 }
 
 .paragraphs-badge:empty {
   display: none;
 }
 
-.paragraph-info {
-  display: -webkit-box;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-box-align: center;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-}
-
-.js .paragraphs-collapsed-description {
+.js .paragraphs-description .paragraphs-content-wrapper,
+.js .paragraphs-description .paragraphs-plugin-wrapper {
   position: relative;
   height: 1.538em;
   overflow: hidden;
-  color: #777;
   word-break: break-all;
   line-height: 1.538em;
+  text-overflow: ellipsis;
 }
 
-.js .paragraphs-collapsed-description::after {
+.js .paragraphs-description .summary-plugin-label::after {
+  content: ": ";
+}
+
+.js .paragraphs-description .summary-content {
+  color: #666666;
+}
+
+.js .paragraphs-description .summary-plugin {
+  display: inline-block;
+  padding-right: 5px;
+  font-size: 0.7rem;
+  color: #888888;
+}
+
+.js .paragraphs-description .summary-plugin:not(:last-child) {
+  border-right: 2px solid #e5e3de;
+}
+
+.js .paragraphs-description .summary-plugin:not(:first-child) {
+  padding: 0 5px;
+}
+
+.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper,
+.js .behavior-active .paragraphs-content {
+  display: none;
+}
+
+.js .behavior-active .paragraphs-behavior {
   display: block;
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 3em;
-  background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(#fff));
-  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%);
-  content: "\00a0";
+}
+
+.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper {
+  display: none;
 }
 
 .paragraph-formatter {
diff --git a/web/modules/paragraphs/css/paragraphs.modal.css b/web/modules/paragraphs/css/paragraphs.modal.css
index 22a368d661..299c77aa76 100644
--- a/web/modules/paragraphs/css/paragraphs.modal.css
+++ b/web/modules/paragraphs/css/paragraphs.modal.css
@@ -8,7 +8,10 @@ ul.paragraphs-add-dialog-list input.field-add-more-submit {
   background-repeat: no-repeat;
   background-position: 10px;
   background-size: auto calc(100% - 10px);
+  margin: 0;
   padding-left: 40px;
+  padding-top: calc(.5rem - 1px);
+  padding-bottom: calc(.5rem - 1px);
   text-align: left;
   border-radius: 3px;
 }
diff --git a/web/modules/paragraphs/css/paragraphs.modal.scss b/web/modules/paragraphs/css/paragraphs.modal.scss
index 0da0fe1ada..96631e5ea6 100644
--- a/web/modules/paragraphs/css/paragraphs.modal.scss
+++ b/web/modules/paragraphs/css/paragraphs.modal.scss
@@ -7,7 +7,10 @@ ul.paragraphs-add-dialog-list {
     background-repeat: no-repeat;
     background-position: 10px;
     background-size: auto calc(100% - 10px);
+    margin: 0;
     padding-left: 40px;
+    padding-top: calc(.5rem - 1px);
+    padding-bottom: calc(.5rem - 1px);
     text-align: left;
     border-radius: 3px;
   }
diff --git a/web/modules/paragraphs/css/paragraphs.widget.css b/web/modules/paragraphs/css/paragraphs.widget.css
index dd6b59b597..a2616b936c 100644
--- a/web/modules/paragraphs/css/paragraphs.widget.css
+++ b/web/modules/paragraphs/css/paragraphs.widget.css
@@ -10,41 +10,57 @@
   text-align: center;
   white-space: nowrap;
   vertical-align: baseline;
+  margin: 3px 0;
 }
 
 .paragraphs-badge:empty {
   display: none;
 }
 
-.paragraph-info {
-  display: -webkit-box;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-box-align: center;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-}
-
-.js .paragraphs-collapsed-description {
+.js .paragraphs-description .paragraphs-content-wrapper,
+.js .paragraphs-description .paragraphs-plugin-wrapper {
   position: relative;
   height: 1.538em;
   overflow: hidden;
-  color: #777;
   word-break: break-all;
   line-height: 1.538em;
+  text-overflow: ellipsis;
+}
+
+.js .paragraphs-description .summary-plugin-label::after {
+  content: ": ";
+}
+
+.js .paragraphs-description .summary-content {
+  color: #666666;
+}
+
+.js .paragraphs-description .summary-plugin {
+  display: inline-block;
+  padding-right: 5px;
+  font-size: 0.7rem;
+  color: #888888;
+}
+
+.js .paragraphs-description .summary-plugin:not(:last-child) {
+  border-right: 2px solid #e5e3de;
 }
 
-.js .paragraphs-collapsed-description::after {
+.js .paragraphs-description .summary-plugin:not(:first-child) {
+  padding: 0 5px;
+}
+
+.js .behavior-active .paragraphs-expanded-description .paragraphs-plugin-wrapper,
+.js .behavior-active .paragraphs-content {
+  display: none;
+}
+
+.js .behavior-active .paragraphs-behavior {
   display: block;
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 3em;
-  background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(#fff));
-  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%);
-  content: "\00a0";
+}
+
+.js .content-active .paragraphs-expanded-description .paragraphs-content-wrapper {
+  display: none;
 }
 
 .paragraphs-icon {
@@ -53,6 +69,7 @@
   width: 20px;
   background: no-repeat center;
   background-size: 16px 16px;
+  vertical-align: middle;
 }
 
 .paragraphs-icon-view {
@@ -142,16 +159,41 @@
   }
 }
 
+.js .field--widget-paragraphs .paragraphs-nested .tabledrag-toggle-weight-wrapper {
+  display: none;
+}
+
 .js .field--widget-paragraphs th .paragraphs-actions {
   float: right;
   margin-right: -11px;
 }
 
+.js .field--widget-paragraphs .form-actions {
+  -webkit-box-align: center;
+  -webkit-align-items: center;
+      -ms-flex-align: center;
+          align-items: center;
+}
+
+.js .field--widget-paragraphs .form-actions .dropbutton-multiple {
+  margin-right: .5rem;
+}
+
+.js .field--widget-paragraphs .form-actions .placeholder {
+  margin-left: .25em;
+}
+
 .js .field--widget-paragraphs .paragraphs-dropbutton-wrapper {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
   display: inline-flex;
+  margin: 0;
+  padding: 0;
+}
+
+.js .field--widget-paragraphs .paragraphs-dropbutton-wrapper .dropbutton-multiple {
+  margin: 0;
 }
 
 .js .field--widget-paragraphs .dropbutton-wrapper {
@@ -160,10 +202,6 @@
   padding-right: 0;
 }
 
-.js .field--widget-paragraphs .dropbutton-widget {
-  position: static;
-}
-
 .js .field--widget-paragraphs .field-multiple-table {
   margin-bottom: 10px;
 }
@@ -177,9 +215,15 @@
 }
 
 .js .field--widget-paragraphs .draggable .tabledrag-handle {
+  min-width: 50px;
   margin-left: 0;
 }
 
+.js .field--widget-paragraphs .draggable .tabledrag-handle:focus::before {
+  margin-left: .1em;
+  margin-right: .1em;
+}
+
 .js .field--widget-paragraphs .tabledrag-handle .handle {
   height: 22px;
 }
@@ -194,13 +238,13 @@
   display: grid;
   -ms-grid-columns: 100px auto 1fr auto;
       grid-template-columns: 100px auto 1fr auto;
-  -ms-grid-rows: auto;
-      grid-template-rows: auto;
-  grid-gap: 5px 5px;
-  -webkit-box-align: center;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
+  -ms-grid-rows: auto auto;
+      grid-template-rows: auto auto;
+  grid-gap: 0 5px;
+  -webkit-box-align: baseline;
+  -webkit-align-items: baseline;
+      -ms-flex-align: baseline;
+          align-items: baseline;
 }
 
 @media (min-width: 992px) {
@@ -233,6 +277,8 @@
   -ms-grid-row: 2;
   -ms-grid-row-span: 1;
   grid-row: 2 / span 1;
+  overflow: hidden;
+  white-space: nowrap;
 }
 
 @media (min-width: 600px) {
@@ -241,8 +287,8 @@
     -ms-grid-column: 3;
     -ms-grid-column-span: 1;
     -ms-grid-row: 1;
-    -ms-grid-row-span: 1;
-    grid-row: 1 / span 1;
+    -ms-grid-row-span: 2;
+    grid-row: 1 / span 2;
   }
 }
 
@@ -269,17 +315,17 @@
   margin-top: 5px;
 }
 
-.draggable:hover .paragraphs-collapsed-description::after {
+.draggable:hover .paragraphs-description::after {
   background: -webkit-gradient(linear, left top, right top, from(rgba(247, 252, 255, 0)), to(#f7fcff));
   background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%);
 }
 
-.drag-previous .paragraphs-collapsed-description::after {
+.drag-previous .paragraphs-description::after {
   background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#ffd));
   background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%);
 }
 
-tr:hover .paragraphs-collapsed-description::after {
+tr:hover .paragraphs-description::after {
   background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 221, 0)), to(#f7fcff));
   background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%);
 }
@@ -305,6 +351,7 @@ tr:hover .paragraphs-collapsed-description::after {
   padding-right: 5px;
   height: 16px;
   width: 16px;
+  vertical-align: middle;
 }
 
 .js .paragraph-type-label {
@@ -315,18 +362,12 @@ tr:hover .paragraphs-collapsed-description::after {
 
 @media (min-width: 600px) {
   .js .paragraph-type-add-modal {
-    width: 100%;
-    padding: 10px 0;
-    height: 30px;
-    margin-top: -1.8em;
-    margin-bottom: -0.2em;
-    display: inline;
+    display: inline-block;
   }
 }
 
 .js .paragraph-type-add-modal-button {
   display: inline-block;
-  margin: 0 auto;
 }
 
 .js .paragraph-type-add-modal-button:hover {
@@ -341,3 +382,37 @@ tr:hover .paragraphs-collapsed-description::after {
 .is-horizontal .paragraphs-tabs .tabs__tab {
   border-bottom: 0;
 }
+
+.paragraphs-behavior {
+  display: none;
+}
+
+.first-paragraph {
+  -webkit-transition: background-color .3s linear;
+  transition: background-color .3s linear;
+}
+
+.paragraph-hover {
+  background-color: #f7fcff;
+}
+
+@media (min-width: 768px) {
+  /* Basic node form sticky paragraph tabs implementation. */
+  .is-horizontal .paragraphs-tabs:first-of-type {
+    position: -webkit-sticky;
+    position: sticky;
+    top: 0;
+    margin-top: 0;
+    padding-top: 5px !important;
+    /* Toolbar bar minimum z-index is 501 so we need to be lower, other way
+       our sticky tabs will be on top of toolbar menu. */
+    z-index: 500;
+    background-color: rgba(255, 255, 255, 0.9);
+  }
+  .toolbar-fixed .is-horizontal .paragraphs-tabs:first-of-type {
+    top: 39px;
+  }
+  .toolbar-fixed.toolbar-horizontal.toolbar-tray-open .is-horizontal .paragraphs-tabs:first-of-type {
+    top: 79px;
+  }
+}
diff --git a/web/modules/paragraphs/css/paragraphs.widget.scss b/web/modules/paragraphs/css/paragraphs.widget.scss
index d38a9611b1..3dedd0b966 100644
--- a/web/modules/paragraphs/css/paragraphs.widget.scss
+++ b/web/modules/paragraphs/css/paragraphs.widget.scss
@@ -14,6 +14,7 @@
     width: $info-size;
     background: no-repeat center;
     background-size: $info-icon-size $info-icon-size;
+    vertical-align: middle;
 
     $icons: view edit-info edit-disabled delete delete-disabled lock changed collapse warning error;
     @each $icon in $icons {
@@ -55,6 +56,7 @@
   }
 }
 
+
 .paragraphs-tabs-wrapper {
   .paragraphs-tabs {
     display: none;
@@ -84,6 +86,9 @@
 // only for JS version of a widget.
 .js {
   .field--widget-paragraphs {
+    .paragraphs-nested .tabledrag-toggle-weight-wrapper {
+      display: none;
+    }
     th .paragraphs-actions {
       float: right;
       // Table th padding is 12px but for some weird reason here we need to do
@@ -91,10 +96,32 @@
       margin-right: -11px;
     }
 
+    // Fix alignment of form-actions.
+    .form-actions {
+      align-items: center;
+
+      // Fix alignment to content.
+      .dropbutton-multiple {
+        margin-right: .5rem;
+      }
+
+      // Add spacing to "to" keyword
+      .placeholder {
+        margin-left: .25em;
+      }
+    }
+
     .paragraphs-dropbutton-wrapper {
       // We are using inline-flex here so 'Add type' dropdown button is inline
       // and aligned 'to type' text.
       display: inline-flex;
+      // Remove margins and paddings that come from Claro theme.
+      margin: 0;
+      padding: 0;
+
+      .dropbutton-multiple {
+        margin: 0;
+      }
     }
 
     .dropbutton-wrapper {
@@ -107,11 +134,6 @@
       padding-right: 0;
     }
 
-    // Reset some CSS that are coming from core.
-    .dropbutton-widget {
-      position: static;
-    }
-
     .field-multiple-table {
       margin-bottom: 10px;
     }
@@ -125,7 +147,16 @@
     }
 
     .draggable .tabledrag-handle {
+      min-width: 50px;
       margin-left: 0;
+
+      // Fix active focus.
+      &:focus {
+        &::before {
+          margin-left: .1em;
+          margin-right: .1em;
+        }
+      }
     }
 
     .tabledrag-handle .handle {
@@ -141,9 +172,9 @@
   .paragraph-top {
     display: grid;
     grid-template-columns: 100px auto 1fr auto;
-    grid-template-rows: auto;
-    grid-gap: $gutter-top $gutter-top;
-    align-items: center;
+    grid-template-rows: auto auto;
+    grid-gap: 0 $gutter-top;
+    align-items: baseline;
 
     @media (min-width: map-get($grid-breakpoints, 'lg')) {
       grid-template-columns: 150px auto 1fr auto;
@@ -169,12 +200,14 @@
       -ms-grid-column: 1;
       -ms-grid-column-span: 5;
       grid-row: 2 / span 1;
+      overflow: hidden;
+      white-space: nowrap;
 
       @media (min-width: map-get($grid-breakpoints, 'sm')) {
         grid-column: 3 / 4;
         -ms-grid-column: 3;
         -ms-grid-column-span: 1;
-        grid-row: 1 / span 1;
+        grid-row: 1 / span 2;
       }
     }
 
@@ -198,20 +231,20 @@
     margin-top: 5px;
   }
 
-  .paragraphs-collapsed-description {
-    @at-root .draggable:hover .paragraphs-collapsed-description {
+  .paragraphs-description {
+    @at-root .draggable:hover .paragraphs-description {
       &::after {
         background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%);
       }
     }
 
-    @at-root .drag-previous .paragraphs-collapsed-description {
+    @at-root .drag-previous .paragraphs-description {
       &::after {
         background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%);
       }
     }
 
-    @at-root tr:hover .paragraphs-collapsed-description {
+    @at-root tr:hover .paragraphs-description {
       &::after {
         background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #f7fcff 100%);
       }
@@ -232,6 +265,7 @@
       padding-right: $gutter-top;
       height: $info-icon-size;
       width: $info-icon-size;
+      vertical-align: middle;
     }
 
     &-label {
@@ -243,18 +277,12 @@
 
   @media (min-width: map-get($grid-breakpoints, 'sm')) {
     .paragraph-type-add-modal {
-      width: 100%;
-      padding: 10px 0;
-      height: 30px;
-      margin-top: -1.8em;
-      margin-bottom: -0.2em;
-      display: inline;
+      display: inline-block;
     }
   }
 
   .paragraph-type-add-modal-button {
     display: inline-block;
-    margin: 0 auto;
   }
 
   .paragraph-type-add-modal-button:hover {
@@ -270,3 +298,38 @@
 .is-horizontal .paragraphs-tabs .tabs__tab {
   border-bottom: 0;
 }
+
+// Requires JavaScript to avoid flickering on pageload.
+.paragraphs-behavior {
+  display: none;
+}
+
+.first-paragraph {
+  transition: background-color .3s linear;
+}
+
+.paragraph-hover {
+  background-color: $paragraph-hover-bg;
+}
+
+@media (min-width: map-get($grid-breakpoints, 'md')) {
+  /* Basic node form sticky paragraph tabs implementation. */
+  .is-horizontal .paragraphs-tabs:first-of-type {
+    position: sticky;
+    top: 0;
+    margin-top: 0;
+    padding-top: 5px !important;
+    /* Toolbar bar minimum z-index is 501 so we need to be lower, other way
+       our sticky tabs will be on top of toolbar menu. */
+    z-index: 500;
+    background-color: rgba(255, 255, 255, 0.9);
+  }
+
+  .toolbar-fixed .is-horizontal .paragraphs-tabs:first-of-type {
+    top: 39px;
+  }
+
+  .toolbar-fixed.toolbar-horizontal.toolbar-tray-open .is-horizontal .paragraphs-tabs:first-of-type {
+    top: 79px;
+  }
+}
diff --git a/web/modules/paragraphs/icons/icon-view.svg b/web/modules/paragraphs/icons/icon-view.svg
index d88023f4c5..e9ef7fcd0f 100644
--- a/web/modules/paragraphs/icons/icon-view.svg
+++ b/web/modules/paragraphs/icons/icon-view.svg
@@ -1,4 +1,4 @@
-<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
-    <path class="bg" d="M0 0h24v24H0z" fill="none"/>
-    <path class="icon" d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13.99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1.42z" fill="#1d84c3"/>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" version="1.1" viewBox="0 0 24 24">
+  <path id="path4" fill="#0074bd" d="m11.83 9l3.17 3.16v-0.16a3 3 0 0 0 -3 -3h-0.17m-4.3 0.8l1.55 1.55c-0.05 0.21-0.08 0.42-0.08 0.65a3 3 0 0 0 3 3c0.22 0 0.44-0.03 0.65-0.08l1.55 1.55c-0.67 0.33-1.41 0.53-2.2 0.53a5 5 0 0 1 -5 -5c0-0.79 0.2-1.53 0.53-2.2m-5.53-5.53l2.28 2.28 0.45 0.45c-1.65 1.3-2.95 3-3.73 5 1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-0.3 4.38-0.84l0.43 0.42 2.92 2.92 1.27-1.27-17.73-17.73m8.73 4a5 5 0 0 1 5 5c0 0.64-0.13 1.26-0.36 1.82l2.93 2.93c1.5-1.25 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74 0.25-4 0.7l2.17 2.15c0.57-0.22 1.18-0.35 1.83-0.35z"/>
 </svg>
diff --git a/web/modules/paragraphs/js/paragraphs.actions.js b/web/modules/paragraphs/js/paragraphs.actions.js
index 3fe7a6cbac..27e2d48f0d 100644
--- a/web/modules/paragraphs/js/paragraphs.actions.js
+++ b/web/modules/paragraphs/js/paragraphs.actions.js
@@ -28,8 +28,13 @@
           $this.toggleClass('open');
         });
 
-        $toggle.on('focusout', function (e) {
-          $this.removeClass('open');
+        $this.on('focusout', function (e) {
+          setTimeout(function () {
+            if ($this.has(document.activeElement).length == 0) {
+              // The focus left the action button group, hide actions.
+              $this.removeClass('open');
+            }
+          }, 1);
         });
       });
     }
diff --git a/web/modules/paragraphs/js/paragraphs.add_above_button.js b/web/modules/paragraphs/js/paragraphs.add_above_button.js
index 14ed1bd816..cc49ca15f8 100644
--- a/web/modules/paragraphs/js/paragraphs.add_above_button.js
+++ b/web/modules/paragraphs/js/paragraphs.add_above_button.js
@@ -8,41 +8,44 @@
   'use strict';
 
   /**
-   * Handle event when "Add above" button is clicked
+   * Handle event when "Add above" button is clicked.
+   *
    * @param event
-   *   clickevent
+   *   Click event.
    */
   var clickHandler = function(event) {
     event.preventDefault();
     var $button = $(this);
-    var $add_more_wrapper = $button.closest('table')
-      .siblings('.clearfix')
-      .find('.paragraphs-add-dialog');
-    var delta = $button.closest('tr').index();
+    var $add_more_wrapper = $button.closest('table').siblings('.clearfix').find('.paragraphs-add-dialog');
+
+    // Find delta for row without interference of unrelated table rows.
+    var $anchorRow = $button.closest('tr');
+    var delta = $anchorRow.parent().find('> .draggable').index($anchorRow);
 
     // Set delta before opening of dialog.
-    var $delta = $add_more_wrapper.closest('.clearfix')
-      .find('.paragraph-type-add-modal-delta');
-    $delta.val(delta);
+    $add_more_wrapper.parent().find('.paragraph-type-add-modal-delta').val(delta);
+
     Drupal.paragraphsAddModal.openDialog($add_more_wrapper, Drupal.t('Add above'));
   };
 
   /**
    * Process paragraph_AddAboveButton elements.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.paragraphsAddAboveButton = {
     attach: function (context, settings) {
-      var button = '<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button js-form-submit form-submit" type="submit" value="' + Drupal.t('Add above') + '">';
-      var $actions = $(context).once().find('.paragraphs-dropdown-actions');
-      $actions.each(function() {
-        if ($(this).closest('.paragraph-top').hasClass('add-above-on')) {
-          $(this).once().prepend(button);
+      $('.paragraphs-dropdown-actions', context).once('paragraphs-add-above-button').each(function () {
+        var $actions = $(this);
+        if ($actions.closest('.paragraph-top').hasClass('add-above-on')) {
+          var $button = $('<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button js-form-submit form-submit" type="submit" value="' + Drupal.t('Add above') + '">');
+          // "Mousedown" is used since the original actions created by paragraphs
+          // use the event "focusout" to hide the actions dropdown.
+          $button.on('mousedown', clickHandler);
+
+          $actions.prepend($button);
         }
       });
-      var $addButtons = $actions.find('.paragraphs-dropdown-action--add-above');
-      // "Mousedown" is used since the original actions created by paragraphs
-      // use the event "focusout" to hide the actions dropdown.
-      $addButtons.on('mousedown', clickHandler);
     }
   };
 
diff --git a/web/modules/paragraphs/js/paragraphs.admin.js b/web/modules/paragraphs/js/paragraphs.admin.js
index 968d334e34..9b1ae6663a 100644
--- a/web/modules/paragraphs/js/paragraphs.admin.js
+++ b/web/modules/paragraphs/js/paragraphs.admin.js
@@ -24,8 +24,6 @@
       $parWidget.removeClass('content-active').addClass('behavior-active');
       $tabContent.removeClass('is-active');
       $tabBehavior.addClass('is-active');
-      $parContent.hide();
-      $parBehavior.show();
     }
     else {
       // Activate content tab visually if there is no previously
@@ -33,12 +31,9 @@
       if (!($mainRegion.hasClass('content-active'))
         && !($mainRegion.hasClass('behavior-active'))) {
         $tabContent.addClass('is-active');
-        $mainRegion.addClass('content-active');
+        $parWidget.addClass('content-active');
       }
 
-      $parContent.show();
-      $parBehavior.hide();
-
       $parTabs.show();
       if ($parBehavior.length === 0) {
         $parTabs.hide();
@@ -58,27 +53,76 @@
   var switchActiveClass = function ($parTabs, $clickedTab, $parWidget) {
       $parTabs.find('li').removeClass('is-active');
       $clickedTab.parent('li').addClass('is-active');
-      $parWidget.removeClass('behavior-active content-active is-active');
+      $parWidget.removeClass('behavior-active content-active');
       $($parWidget).find($clickedTab.attr('href')).addClass('is-active');
 
       if ($parWidget.find('#content').hasClass('is-active')) {
-        $parWidget.find('.layout-region-node-main').addClass('content-active');
-        $parWidget.find('.paragraphs-content').show();
-        $parWidget.find('.paragraphs-behavior').hide();
+        $parWidget.addClass('content-active');
+        $parWidget.find('.paragraphs-add-wrapper').parent().removeClass('hidden');
+      }
+      else if ($parWidget.find('#behavior').hasClass('is-active')) {
+        $parWidget.addClass('behavior-active');
+        $parWidget.find('.paragraphs-add-wrapper').parent().addClass('hidden');
       }
+  };
+
+  /**
+   * Add class to first paragraph in the viewport.
+   *
+   * In order to have a persistent position when switching tabs,
+   * we add a class to the first paragraph visible in the viewport.
+   */
+  var markFirstVisibleParagraph = function (totalTopOffset) {
+    var $window = $(window);
+    var bottomOfScreen = $window.scrollTop() + $window.height();
+    var topOfScreen = $window.scrollTop() + totalTopOffset;
+    var $firstParagraph = false;
+    // @todo Make sure to skip non-Paragraph draggable field widget items here.
+    var $allParagraphs = $('.node-form .draggable');
 
-      if ($parWidget.find('#behavior').hasClass('is-active')) {
-        $parWidget.find('.layout-region-node-main').addClass('behavior-active');
-        $parWidget.find('.paragraphs-content').hide();
-        $parWidget.find('.paragraphs-behavior').show();
+    $allParagraphs.each(function () {
+      var $this = $(this);
+      var topOfElement = $this.offset().top;
+      var bottomOfElement = $this.offset().top + $this.height();
+
+      // Search for paragraphs inside the viewport.
+      if ((bottomOfScreen > topOfElement) && (topOfScreen < bottomOfElement)) {
+        if ($firstParagraph) {
+          // Find next best Paragraph in Viewport.
+          if (topOfElement > topOfScreen ) {
+            // Second top in screen or first nested in screen.
+            $firstParagraph = $this;
+            return false;
+          }
+          else if(topOfElement > bottomOfScreen) {
+            // Choose previous element.
+            return false;
+          }
+        }
+
+        $firstParagraph = $this;
+        if (topOfScreen < topOfElement) {
+          // Choose this element as it starts in viewport.
+          return false;
+        }
       }
+    });
+
+    if ($firstParagraph) {
+      // Remove potential previous marker.
+      $('.first-paragraph').removeClass('first-paragraph');
+      // Add the class to the first paragraph in the viewport.
+      $firstParagraph.addClass('first-paragraph paragraph-hover');
+    }
+
+    return $firstParagraph;
   };
 
   /**
-  * For body tag, adds tabs for selecting how the content will be displayed.
-  *
-  * @type {Drupal~behavior}
-  */
+   * For body tag, adds tabs for selecting how the content will be displayed.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.bodyTabs = {
     attach: function (context) {
       var $topLevelParWidgets = $('.paragraphs-tabs-wrapper', context).filter(function() {
@@ -92,8 +136,39 @@
 
         // Create click event.
         $parTabs.find('a').click(function(e) {
+          var toolbarHeight = $('.toolbar-tray-horizontal').outerHeight() || 0;
+          var adminToolbarsOffset = $('#toolbar-bar').outerHeight() + toolbarHeight;
+          var totalTopOffset = adminToolbarsOffset + $('.paragraphs-tabs').outerHeight();
+          var $firstParagraph;
+          var currentParagraphOffset = 0;
+          var $window = $(window);
+
+          $firstParagraph = markFirstVisibleParagraph(totalTopOffset);
+
+          // Set the proper window position for each tab.
+          if ($firstParagraph) {
+            // Maintain vertical offset in addition to the toolbar heights.
+            currentParagraphOffset = $firstParagraph.offset().top - ($window.scrollTop() + totalTopOffset);
+            // Ignore a negative offset.
+            if (currentParagraphOffset < 0) {
+              currentParagraphOffset = 0;
+            }
+          }
+
           e.preventDefault();
           switchActiveClass($parTabs, $(this), $parWidget);
+
+          // We need to check to which position to scroll to, whenever we need to scroll.
+          // If the first paragraph is the same, we maintain the scroll position, otherwise scroll to top of the paragraph.
+          if ($firstParagraph) {
+            $('html, body').scrollTop($firstParagraph.offset().top - totalTopOffset - currentParagraphOffset);
+
+            // Reset the first paragraph class with a delay, in order for the background change to be visible.
+            setTimeout(function() {
+              $('.first-paragraph').removeClass('paragraph-hover');
+            }, 1000);
+          }
+
         });
       });
 
diff --git a/web/modules/paragraphs/js/paragraphs.dragdrop.js b/web/modules/paragraphs/js/paragraphs.dragdrop.js
index 3a8c33fba8..5373f6f863 100644
--- a/web/modules/paragraphs/js/paragraphs.dragdrop.js
+++ b/web/modules/paragraphs/js/paragraphs.dragdrop.js
@@ -80,19 +80,17 @@
        *   The Sortable event.
        */
       function handleReorder(evt) {
-        var $item = $(evt.item);
-        var $parent = $item.closest('.paragraphs-dragdrop__list');
-        var $children = $parent.children('li');
-        var $srcParent = $(evt.to);
-        var $srcChildren = $srcParent.children('li');
-
         // Update both the source and target children.
-        updateWeightsAndPath($srcChildren);
-        updateWeightsAndPath($children);
+        if (evt.from === evt.to) {
+          updateWeightsAndPath($(evt.to).children('li'));
+        }
+        else {
+          updateWeightsAndPath($(evt.from).children('li'));
+          updateWeightsAndPath($(evt.to).children('li'));
+        }
         endDragClasses();
       }
 
-
       /**
        * Update weight and recursively update path of the provided paragraphs.
        *
@@ -236,6 +234,12 @@
        */
       function startDragClasses() {
         $('html').addClass('is-dragging-paragraphs');
+        // Fix race condition when the drag event start results in a scrollbar
+        // position change triggered by a collapsing item with children. Add a
+        // min-height for the current height as a workaround.
+        $('.paragraphs-dragdrop__list').eq(0).css('min-height', function() {
+          return $(this).height();
+        });
       }
 
       /**
@@ -260,6 +264,8 @@
       function endDragClasses() {
         $('html').removeClass('is-dragging-paragraphs');
         $('.is-droppable-target').removeClass('is-droppable-target');
+        // Remove the custom min-height definition added in startDragClasses().
+        $('.paragraphs-dragdrop__list').eq(0).removeAttr('style');
       }
 
       // Fix for an iOS 10 bug. Binding empty event handler on the touchmove
diff --git a/web/modules/paragraphs/js/paragraphs.modal.js b/web/modules/paragraphs/js/paragraphs.modal.js
index 55a12a2324..16128f17aa 100644
--- a/web/modules/paragraphs/js/paragraphs.modal.js
+++ b/web/modules/paragraphs/js/paragraphs.modal.js
@@ -3,28 +3,25 @@
  *
  */
 
-(function ($, Drupal, drupalSettings) {
+(function ($, Drupal) {
 
   'use strict';
 
   /**
    * Click handler for click "Add" button between paragraphs.
    *
-   * @type {Object}
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.paragraphsModalAdd = {
     attach: function (context) {
-      $('.paragraph-type-add-modal-button', context)
-        .once('add-click-handler')
-        .on('click', function (event) {
-          var $button = $(this);
-          var $add_more_wrapper = $button.parent().siblings('.paragraphs-add-dialog');
-          Drupal.paragraphsAddModal.openDialog($add_more_wrapper, $button.val());
+      $('.paragraph-type-add-modal-button', context).once('add-click-handler').on('click', function (event) {
+        var $button = $(this);
+        Drupal.paragraphsAddModal.openDialog($button.parent().siblings('.paragraphs-add-dialog'), $button.val());
 
-          // Stop default execution of click event.
-          event.preventDefault();
-          event.stopPropagation();
-        });
+        // Stop default execution of click event.
+        event.preventDefault();
+        event.stopPropagation();
+      });
     }
   };
 
@@ -38,41 +35,55 @@
   /**
    * Open modal dialog for adding new paragraph in list.
    *
-   * @param {Object} $context
-   *   jQuery element of form wrapper used to submit request for adding new
-   *   paragraph to list. Wrapper also contains dialog template.
+   * @param {Object} element
+   *   The element that holds the dialog.
    * @param {string} title
-   *   The title of the modal form window.
+   *   The title of the dialog.
+   *
+   * @return {Object}
+   *   Dialog object.
    */
-  Drupal.paragraphsAddModal.openDialog = function ($context, title) {
+  Drupal.paragraphsAddModal.openDialog = function (element, title) {
+    var $element = $(element);
 
-    $context.dialog({
-      modal: true,
+    // Get the delta element before moving $element to dialog element.
+    var $modalDelta = $element.parent().find('.paragraph-type-add-modal-delta');
+
+    // Deep clone with all attached events. We need to work on cloned element
+    // and not directly on origin because Drupal dialog.ajax.js
+    // Drupal.behaviors.dialog will do remove of origin element on dialog close.
+    $element = $element.clone(true);
+
+    var dialog = Drupal.dialog($element, {
+      // Turn off autoResize from dialog.position so draggable is not disabled.
+      autoResize: false,
       resizable: false,
       title: title,
       width: 'auto',
-      close: function () {
-        var $dialog = $(this);
-
-        // Destroy dialog object.
-        $dialog.dialog('destroy');
-        // Reset delta after destroying the dialog object.
-        var $delta = $dialog.closest('.clearfix')
-          .find('.paragraph-type-add-modal-delta');
-        $delta.val('');
-      }
+      paragraphsModalDelta: $modalDelta,
     });
+    dialog.showModal();
 
     // Close the dialog after a button was clicked.
-    $('.field-add-more-submit', $context)
-      .each(function () {
-      // Use mousedown event, because we are using ajax in the modal add mode
-      // which explicitly suppresses the click event.
-      $(this).on('mousedown', function () {
-        var $this = $(this);
-        $this.closest('div.ui-dialog-content').dialog('close');
-      });
+    // Use mousedown event, because we are using ajax in the modal add mode
+    // which explicitly suppresses the click event.
+    $element.once().find('.field-add-more-submit').on('mousedown', function () {
+      dialog.close();
     });
+
+    return dialog;
   };
 
-}(jQuery, Drupal, drupalSettings));
+  $(window).on({
+    'dialog:afterclose': function (event, dialog, $element) {
+      // Check first if dialog instance exist because dialog:afterclose will
+      // be triggered two times, first from once from dialog.ajax.js
+      // Drupal.behaviors.dialog and second time from dialog.js.
+      if ($element.dialog('instance') && $element.dialog('option', 'paragraphsModalDelta')) {
+        // Reset modal delta value.
+        $element.dialog('option', 'paragraphsModalDelta').val('');
+      }
+    }
+  });
+
+})(jQuery, Drupal);
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml b/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml
index 260d688c26..5ec43b62b3 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml
+++ b/web/modules/paragraphs/modules/paragraphs_demo/config/install/paragraphs.paragraphs_type.text_image.yml
@@ -3,4 +3,4 @@ status: true
 dependencies: {  }
 id: text_image
 label: 'Text + Image'
-description: 'Use <em>Test + Image</em> for adding a text on the left and an image  on the right.'
\ No newline at end of file
+description: 'Use <em>Text + Image</em> for adding a text on the left and an image  on the right.'
\ No newline at end of file
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
index de41a4d88d..6fc2685385 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
@@ -1,5 +1,5 @@
 description: 'Provides multilingual demo Paragraphs types.'
-# core: 8.x
+core_version_requirement: ^8.7.7 || ^9
 dependencies:
   - paragraphs:paragraphs
   - drupal:field
@@ -21,8 +21,7 @@ name: Paragraphs Demo
 package: Paragraphs
 type: module
 
-# Information added by Drupal.org packaging script on 2019-02-20
-version: '8.x-1.6'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-02-16
+version: '8.x-1.11'
 project: 'paragraphs'
-datestamp: 1550669588
+datestamp: 1581850832
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install
index 8373cb80db..5c04a4db22 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install
+++ b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.install
@@ -13,8 +13,10 @@
  * Implements hook_install().
  */
 function paragraphs_demo_install() {
-  // Ensure the translation fields are created in the database.
-  \Drupal::service('entity.definition_update_manager')->applyUpdates();
+  if (version_compare(\Drupal::VERSION, '8.6.99', '<=')) {
+    // Ensure the translation fields are created in the database.
+    \Drupal::service('entity.definition_update_manager')->applyUpdates();
+  }
 
   // Create three paragraphs to structure the content.
   $paragraph = Paragraph::create([
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
similarity index 94%
rename from web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php
rename to web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
index d62cbb4f02..a4cb734666 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/src/Tests/ParagraphsDemoTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
@@ -1,16 +1,16 @@
 <?php
 
-namespace Drupal\paragraphs_demo\Tests;
+namespace Drupal\Tests\paragraphs_demo\Functional;
 
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 
 /**
  * Tests the demo module for Paragraphs.
  *
  * @group paragraphs
  */
-class ParagraphsDemoTest extends WebTestBase {
+class ParagraphsDemoTest extends BrowserTestBase {
 
   use ParagraphsCoreVersionUiTestTrait;
 
@@ -24,6 +24,11 @@ class ParagraphsDemoTest extends WebTestBase {
     'block',
   );
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -37,7 +42,7 @@ protected function setUp() {
   /**
    * Asserts demo paragraphs have been created.
    */
-  protected function testConfigurationsAndCreation() {
+  public function testConfigurationsAndCreation() {
 
     // Assert that the demo page is displayed to anymous users.
     $this->drupalGet('');
@@ -76,7 +81,7 @@ protected function testConfigurationsAndCreation() {
 
     // Set edit mode to open.
     $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display');
-    $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_demo_settings_edit");
+    $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit");
     $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
diff --git a/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml b/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml
index b1f79712e3..372e5d0629 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml
+++ b/web/modules/paragraphs/modules/paragraphs_library/config/optional/views.view.paragraphs_library_browser.yml
@@ -166,6 +166,7 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
+          use_field_cardinality: true
           entity_type: paragraphs_library_item
           plugin_id: entity_browser_select
         label:
diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
index d1442c8b8b..6186fe0e98 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
@@ -1,7 +1,7 @@
 name: Paragraphs Library
 type: module
 description: 'Provides a library for reusing paragraphs.'
-# core: 8.x
+core_version_requirement: ^8.7.7 || ^9
 package: Paragraphs
 configure: paragraphs_library_item.settings
 dependencies:
@@ -11,8 +11,7 @@ dependencies:
 test_dependencies:
   - entity_browser:entity_browser
 
-# Information added by Drupal.org packaging script on 2019-02-20
-version: '8.x-1.6'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-02-16
+version: '8.x-1.11'
 project: 'paragraphs'
-datestamp: 1550669588
+datestamp: 1581850832
diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install
index 1e66860898..1751ed9f35 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install
+++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.install
@@ -6,7 +6,6 @@
  */
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\paragraphs_library\Entity\LibraryItem;
@@ -45,6 +44,20 @@ function paragraphs_library_install() {
     $entity_usage_config->set('local_task_enabled_entity_types', $tabs_enabled)
       ->save();
   }
+
+  // Enable the usage warning message on edit and delete forms.
+  $edit_warning_enabled = $entity_usage_config->get('edit_warning_message_entity_types') ?: [];
+  if (!in_array('paragraphs_library_item', $edit_warning_enabled)) {
+    $edit_warning_enabled[] = 'paragraphs_library_item';
+    $entity_usage_config->set('edit_warning_message_entity_types', $edit_warning_enabled)
+      ->save();
+  }
+  $delete_warning_enabled = $entity_usage_config->get('delete_warning_message_entity_types') ?: [];
+  if (!in_array('paragraphs_library_item', $delete_warning_enabled)) {
+    $delete_warning_enabled[] = 'paragraphs_library_item';
+    $entity_usage_config->set('delete_warning_message_entity_types', $delete_warning_enabled)
+      ->save();
+  }
 }
 
 /**
@@ -52,7 +65,7 @@ function paragraphs_library_install() {
  */
 function paragraphs_library_update_8001() {
 
-  \Drupal::service('entity.manager')->clearCachedDefinitions();
+  \Drupal::service('entity_type.manager')->clearCachedDefinitions();
 
   // Load all library items and store their values in memory.
   $library_values = \Drupal::database()->query('SELECT * FROM {paragraphs_library_item}')->fetchAll(PDO::FETCH_ASSOC);
@@ -87,7 +100,6 @@ function paragraphs_library_update_8001() {
     ->setRevisionable(TRUE)
     ->setTranslatable(TRUE);
 
-
   $default_langcode_field = BaseFieldDefinition::create('boolean')
     ->setLabel(t('Default translation'))
     ->setDescription(t('A flag indicating whether this is the default translation.'))
@@ -98,7 +110,7 @@ function paragraphs_library_update_8001() {
   $entity_definition_update_manager->installFieldStorageDefinition('langcode', $entity_type->id(), 'paragraphs_library', $langcode_field);
   $entity_definition_update_manager->installFieldStorageDefinition('default_langcode', $entity_type->id(), 'paragraphs_library', $default_langcode_field);
 
-  \Drupal::entityManager()->clearCachedDefinitions();
+  \Drupal::entityTypeManager()->clearCachedDefinitions();
   foreach ($library_values as $library_value) {
     $library_value['paragraphs'] = [
       'target_id' => $library_value['paragraphs__target_id'],
@@ -339,3 +351,22 @@ function paragraphs_library_update_8101() {
       ->save();
   }
 }
+
+/**
+ * Enable the usage warning message on edit and delete forms.
+ */
+function paragraphs_library_update_8102() {
+  $entity_usage_config = \Drupal::configFactory()->getEditable('entity_usage.settings');
+  $edit_warning_enabled = $entity_usage_config->get('edit_warning_message_entity_types') ?: [];
+  if (!in_array('paragraphs_library_item', $edit_warning_enabled)) {
+    $edit_warning_enabled[] = 'paragraphs_library_item';
+    $entity_usage_config->set('edit_warning_message_entity_types', $edit_warning_enabled)
+      ->save();
+  }
+  $delete_warning_enabled = $entity_usage_config->get('delete_warning_message_entity_types') ?: [];
+  if (!in_array('paragraphs_library_item', $delete_warning_enabled)) {
+    $delete_warning_enabled[] = 'paragraphs_library_item';
+    $entity_usage_config->set('delete_warning_message_entity_types', $delete_warning_enabled)
+      ->save();
+  }
+}
diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
index 43436e4a23..8c55ac14a6 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
+++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
@@ -155,21 +155,6 @@ function paragraphs_library_views_pre_render(ViewExecutable $view) {
   }
 }
 
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function paragraphs_library_form_paragraphs_library_item_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
-  $library_item = $form_state->getFormObject()->getEntity();
-  $usage_data = \Drupal::service('entity_usage.usage')->listSources($library_item);
-
-  if ($usage_data) {
-    $usage_count = _paragraphs_library_count_usage($usage_data);
-    \Drupal::messenger()->addWarning(\Drupal::translation()->formatPlural($usage_count, 'Library item is used 1 time.', 'Library item is used @count times.', [
-      '@count' => $usage_count,
-    ]));
-  }
-}
-
 /**
  * Counts the usage across all entities.
  *
@@ -256,7 +241,7 @@ function paragraphs_library_library_item_unlink_submit(array $form, FormStateInt
   // Make a copy of the paragraph. Use the Replicate module, if it is enabled.
   /** @var \Drupal\Core\Entity\EntityInterface $original_paragraph */
   if (\Drupal::hasService('replicate.replicator')) {
-    $duplicate_paragraph = \Drupal::getContainer()->get('replicate.replicator')->replicateEntity($original_paragraph);
+    $duplicate_paragraph = \Drupal::getContainer()->get('replicate.replicator')->cloneEntity($original_paragraph);
   }
   else {
     $duplicate_paragraph = $original_paragraph->createDuplicate();
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
index 366e23effe..302f06063f 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
@@ -6,9 +6,7 @@
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Url;
 use Drupal\paragraphs_library\Entity\LibraryItem;
 use Drupal\paragraphs_library\LibraryItemInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -191,4 +189,5 @@ protected function getRevisionIds(LibraryItemInterface $library_item) {
       ->execute();
     return array_keys($result);
   }
+
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
index f0641630cc..3dfe46a230 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
@@ -17,6 +17,13 @@
  * @ContentEntityType(
  *   id = "paragraphs_library_item",
  *   label = @Translation("Paragraphs library item"),
+ *   label_collection = @Translation("Paragraphs library items"),
+ *   label_singular = @Translation("Paragraphs library item"),
+ *   label_plural = @Translation("Paragraphs library items"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count Paragraphs library item",
+ *     plural = "@count Paragraphs library items",
+ *   ),
  *   handlers = {
  *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
  *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
@@ -255,19 +262,18 @@ public static function createFromParagraph(ParagraphInterface $paragraph) {
     }
     $duplicate_paragraph->save();
 
-    $label = static::buildLabel($paragraph);
     $library_item = static::create([
-      'label' => $label,
       'paragraphs' => $duplicate_paragraph,
+      'langcode' => $paragraph->language()->getId(),
     ]);
 
-    // Add a translation for each translation the paragraph has, the only
-    // translatable element is the label. The referenced paragraph keeps the
-    // existing translations.
-    foreach ($duplicate_paragraph->getTranslationLanguages(FALSE) as $langcode => $language) {
-      $library_item->addTranslation($langcode, [
-        'label' => static::buildLabel($duplicate_paragraph->getTranslation($langcode))
-      ] + $library_item->toArray());
+    // Build the label in each available translation and ensure the translations
+    // exist.
+    foreach ($duplicate_paragraph->getTranslationLanguages() as $langcode => $language) {
+      if (!$library_item->hasTranslation($langcode)) {
+        $library_item->addTranslation($langcode, $library_item->toArray());
+      }
+      $library_item->getTranslation($langcode)->set('label', static::buildLabel($duplicate_paragraph->getTranslation($langcode)));
     }
 
     return $library_item;
@@ -282,8 +288,8 @@ public static function createFromParagraph(ParagraphInterface $paragraph) {
    * @return string
    */
   protected static function buildLabel(ParagraphInterface $paragraph) {
-    $summary = $paragraph->getSummary(['show_behavior_summary' => FALSE]);
-    $summary = Unicode::truncate($summary, 50);
+    $summary = $paragraph->getSummaryItems(['show_behavior_summary' => FALSE]);
+    $summary = Unicode::truncate(implode(', ', $summary['content']), 50);
     return $paragraph->getParagraphType()->label() . ': ' . $summary;
   }
 
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
index 93a392dd67..a2ed4c6124 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
@@ -3,10 +3,10 @@
 namespace Drupal\paragraphs_library\Form;
 
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Messenger\MessengerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Component\Datetime\TimeInterface;
 
@@ -21,39 +21,25 @@ class LibraryItemForm extends ContentEntityForm {
   protected $entity;
 
   /**
-   * Provides messenger service.
-   *
-   * @var \Drupal\Core\Messenger\Messenger
-   */
-  protected $messenger;
-
-  /**
-   * Constructs a LibraryItemForm object.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Messenger\Messenger $messenger
-   *   The messenger service.
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   The entity type bundle service.
-   * @param \Drupal\Component\Datetime\TimeInterface $time
-   *   The time service.
+   * {@inheritdoc}
    */
-  public function __construct(EntityManagerInterface $entity_manager, Messenger $messenger, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
-    parent::__construct($entity_manager, $entity_type_bundle_info, $time);
-    $this->messenger = $messenger;
+  public function getFormId() {
+    // If the entity is not new, add the entity id. This will allow having more
+    // than one form open when editing a library item within another.
+    // To alter this form use hook_form_BASE_FORM_ID_alter.
+    if ($this->entity->id()) {
+      return 'paragraphs_library_item_edit_form_' . $this->entity->id();
+    }
+    return 'paragraphs_library_item_edit_form';
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.manager'),
-      $container->get('messenger'),
-      $container->get('entity_type.bundle.info'),
-      $container->get('datetime.time')
-    );
+    $form = parent::create($container);
+    $form->setMessenger($container->get('messenger'));
+    return $form;
   }
 
   /**
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php
index 1d733468b0..33dc748246 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionDeleteForm.php
@@ -6,7 +6,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -47,10 +47,10 @@ class LibraryItemRevisionDeleteForm extends ConfirmFormBase {
    *   The entity type manager service.
    * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
    *   The date formatter service.
-   * @param \Drupal\Core\Messenger\Messenger $messenger
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, Messenger $messenger) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, MessengerInterface $messenger) {
     $this->entityTypeManager = $entity_type_manager;
     $this->dateFormatter = $date_formatter;
     $this->messenger = $messenger;
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
index 2eb88f9d66..3d2f3fb61e 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
@@ -7,7 +7,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Url;
 use Drupal\paragraphs_library\LibraryItemInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -58,10 +58,10 @@ class LibraryItemRevisionRevertForm extends ConfirmFormBase {
    *   The date formatter service.
    * @param \Drupal\Component\Datetime\TimeInterface $time
    *   The time service.
-   * @param \Drupal\Core\Messenger\Messenger $messenger
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, TimeInterface $time, Messenger $messenger) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, DateFormatterInterface $date_formatter, TimeInterface $time, MessengerInterface $messenger) {
     $this->entityTypeManager = $entity_type_manager;
     $this->dateFormatter = $date_formatter;
     $this->time = $time;
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php b/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php
index 7c2e5b0e3e..2260ed16e5 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/LibraryItemAccessControlHandler.php
@@ -19,13 +19,6 @@ class LibraryItemAccessControlHandler extends EntityAccessControlHandler {
    * {@inheritdoc}
    */
   protected function checkAccess(EntityInterface $library_item, $operation, AccountInterface $account) {
-    if ($operation == 'delete') {
-      $usage_data = \Drupal::service('entity_usage.usage')->listSources($library_item);
-      if ($usage_data) {
-        return AccessResult::forbidden();
-      }
-    }
-
     // In case a library item is unpublished, only allow access if a user has
     // administrative permission. Ensure to collect the required cacheability
     // metadata and combine both the published and the referenced access check
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php
index c216340c27..195dd07b0c 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Validation/Constraint/ParagraphsLibraryItemHasAllowedParagraphsTypeConstraintValidator.php
@@ -94,23 +94,25 @@ public function validate($value, Constraint $constraint) {
         /** @var \Drupal\paragraphs_library\LibraryItemInterface $library_item_entity */
         foreach ($paragraph->get($field_name) as $entity_reference_item) {
           // Get the Paragraphs type of the library item.
-          $library_item_entity = $entity_reference_item->entity;
-          $used_paragraphs_type = $library_item_entity->get('paragraphs')->entity->getType();
-
-          // Check if the Paragraphs type of the item is not allowed in the
-          // field holding the parent Paragraph.
-          if (in_array($used_paragraphs_type, $allowed_paragraphs_types)) {
-            continue;
+          if ($library_item_entity = $entity_reference_item->entity) {
+            if ($used_paragraphs = $library_item_entity->get('paragraphs')->entity) {
+              $used_paragraphs_type = $used_paragraphs->getType();
+              // Check if the Paragraphs type of the item is not allowed in the
+              // field holding the parent Paragraph.
+              if (in_array($used_paragraphs_type, $allowed_paragraphs_types)) {
+                continue;
+              }
+
+              $paragraphs_type_entity = $this->entityTypeManager->getStorage('paragraphs_type')->load($used_paragraphs_type);
+
+              $this->context->addViolation($constraint->message, [
+                '@library_item_field_label' => $field_definition->getLabel(),
+                '@paragraphs_type_label' => $paragraphs_type_entity->label(),
+                '@paragraph_field_label' => $value->getFieldDefinition()->getLabel(),
+              ]);
+            }
           }
 
-          $paragraphs_type_entity = $this->entityTypeManager->getStorage('paragraphs_type')->load($used_paragraphs_type);
-
-          $this->context->addViolation($constraint->message, [
-            '@library_item_field_label' => $field_definition->getLabel(),
-            '@paragraphs_type_label' => $paragraphs_type_entity->label(),
-            '@paragraph_field_label' => $value->getFieldDefinition()->getLabel(),
-          ]);
-
         }
       }
     }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
similarity index 88%
rename from web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php
rename to web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
index 8454c9a92b..8e87363ead 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/MultilingualBehaviorTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
@@ -1,9 +1,9 @@
 <?php
 
-namespace Drupal\paragraphs_library\Tests;
+namespace Drupal\Tests\paragraphs_library\Functional;
 
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\paragraphs\Tests\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
 
 /**
  * Tests paragraphs library multilingual functionality.
@@ -79,8 +79,8 @@ public function setUp() {
   public function testReuseTranslationForNestedParagraphFromLibrary() {
     // Add nested paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph.',
@@ -99,7 +99,7 @@ public function testReuseTranslationForNestedParagraphFromLibrary() {
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
@@ -138,8 +138,8 @@ public function testMoveTranslatedNestedParagraphToLibrary() {
 
     // Add node with text paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph',
@@ -158,7 +158,7 @@ public function testMoveTranslatedNestedParagraphToLibrary() {
 
     // Convert translated paragraph to library.
     $this->drupalGet($node->toUrl('edit-form'));
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_promote_to_library');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_promote_to_library');
     $this->drupalPostForm(NULL, NULL, 'Save (this translation)');
 
     // Check translation.
@@ -181,8 +181,8 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
 
     // Add paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.'
@@ -201,7 +201,7 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
@@ -225,7 +225,7 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
     $this->drupalGet('node/' . $node->id());
     $this->assertText('En label Example text for test.');
     $this->clickLink('Edit');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_unlink_from_library');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_unlink_from_library');
     $this->assertText('En label Example text for test.');
   }
 
@@ -237,8 +237,8 @@ public function testDetachBeforeTranslation() {
 
     // Add paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.'
@@ -257,12 +257,12 @@ public function testDetachBeforeTranslation() {
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_unlink_from_library');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_unlink_from_library');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
     ];
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
index 7853987a0c..1e91637d12 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
@@ -2,11 +2,11 @@
 
 namespace Drupal\Tests\paragraphs_library\Functional;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\node\Entity\Node;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
 /**
@@ -30,6 +30,11 @@ class ParagraphsLibraryItemTest extends BrowserTestBase {
     'field_ui',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'classy';
+
   /**
    * {@inheritdoc}
    */
@@ -293,6 +298,7 @@ public function testLibraryItemUsageTab() {
     $assert_session->elementContains('css', 'table tbody tr td:nth-child(2)', 'Paragraph');
     $assert_session->elementContains('css', 'table tbody tr td:nth-child(3)', 'English');
     $assert_session->elementContains('css', 'table tbody tr td:nth-child(4)', 'Reusable paragraph');
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(5)', 'Published');
 
     // Assert breadcrumb.
     $assert_session->elementContains('css', '.breadcrumb ol li:nth-child(1)', 'Home');
@@ -311,13 +317,48 @@ public function testLibraryItemUsageTab() {
     $this->clickLink('Usage');
     $assert_session->pageTextContains('Entity usage information for Test usage nested paragraph');
 
-    // No usage shows up on this page.
-    // @todo once 2954039 lands, we expect to have a row here indicating that
-    // the host node references the paragraph in a non-default revision.
-    // Alternatively, if 2971131 lands first, we would have here an extra row
-    // with possibly a generic label (just with the entity ID or similar). In
-    // both cases this test will need to be updated.
-    $assert_session->elementNotExists('css', 'table tbody tr');
+    // Assert there is a row here indicating that the host node references the
+    // paragraph in a non-default revision.
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(1)', 'Test content &gt; field_paragraphs (previous revision)');
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(2)', 'Paragraph');
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(3)', 'English');
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(4)', 'Reusable paragraph');
+    $assert_session->elementContains('css', 'table tbody tr td:nth-child(5)', 'Published');
+  }
+
+  /**
+   * Test if the usage warning message shows up, when deleting a library item.
+   */
+  public function testLibraryItemDeleteWarningMessage() {
+    $page = $this->getSession()->getPage();
+    $assert_session = $this->assertSession();
+
+    // Create a paragraph in the library.
+    $this->drupalGet('admin/content/paragraphs/add/default');
+    $page->pressButton('Add text');
+
+    $edit = [
+      'label[0][value]' => 'Test usage warning message',
+      'paragraphs[0][subform][field_text][0][value]' => 'Example text.',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $assert_session->pageTextContains('Paragraph Test usage warning message has been created.');
+
+    // Create content with referenced paragraph.
+    $this->drupalGet('node/add/paragraphed_test');
+    $page->pressButton('Add From library');
+    $edit = [
+      'title[0][value]' => 'Test content',
+      'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'Test usage warning message',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+
+    $node = $this->drupalGetNodeByTitle('Test content');
+    $library_item = $node->get('field_paragraphs')->entity->get('field_reusable_paragraph')->entity;
+
+    // Check if there is a warning message on the delete form.
+    $this->drupalGet('/admin/content/paragraphs/' . $library_item->id() . '/delete');
+    $assert_session->pageTextContains('There are recorded usages of this entity.');
   }
 
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
index fb1ca21730..3fd2014f97 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\Tests\paragraphs_library\Functional;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\Tests\BrowserTestBase;
@@ -36,6 +36,11 @@ class ParagraphsLibraryItemTranslationTest extends BrowserTestBase {
     'content_translation',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -85,6 +90,7 @@ public function testLibraryItemTranslation() {
       'settings[paragraph][text][translatable]' => TRUE,
       'settings[paragraph][text][fields][field_text]' => TRUE,
       'settings[paragraphs_library_item][paragraphs_library_item][translatable]' => TRUE,
+      'settings[node][paragraphed_test][settings][language][language_alterable]' => TRUE
     ];
     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
 
@@ -143,6 +149,37 @@ public function testLibraryItemTranslation() {
     $this->clickLink('Edit', 1);
     $assert_session->fieldValueEquals('Label', 'text: DE Library text');
     $assert_session->fieldValueEquals('Text', 'DE Library text');
+
+    // Add a node with a text paragraph.
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $edit = [
+      'title[0][value]' => 'DE Llama Test',
+      'langcode[0][value]' => 'de',
+      'field_paragraphs[0][subform][field_text][0][value]' => 'DE Text Paragraph',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $assert_session->pageTextContains('paragraphed_test DE Llama Test has been created.');
+
+    // Translate the node to the default language.
+    $this->clickLink('Translate');
+    $this->clickLink('Add');
+    $edit = [
+      'title[0][value]' => 'EN Llama Test',
+      'field_paragraphs[0][subform][field_text][0][value]' => 'EN Library text',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save (this translation)');
+    $assert_session->pageTextContains('paragraphed_test EN Llama Test has been updated.');
+
+    // Assert the original node can promote paragraphs to the library.
+    $node = $this->drupalGetNodeByTitle('DE Llama Test');
+    $this->drupalGet('de/node/' . $node->id() . '/edit');
+    $page->pressButton('field_paragraphs_0_promote_to_library');
+    $assert_session->fieldValueEquals('Reusable paragraph', 'text: DE Text Paragraph (2)');
+    $this->drupalPostForm(NULL, NULL, 'Save');
+    $assert_session->pageTextContains('paragraphed_test DE Llama Test has been updated.');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $assert_session->pageTextContains('Reusable paragraph');
   }
 
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
similarity index 88%
rename from web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php
rename to web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
index b74f5686bc..5986cf5623 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Tests/ParagraphsLibraryItemTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
@@ -1,19 +1,16 @@
 <?php
 
-namespace Drupal\paragraphs_library\Tests;
+namespace Drupal\Tests\paragraphs_library\Functional;
 
 use Drupal\Core\Url;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\paragraphs\Tests\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
 
 /**
  * Tests paragraphs library functionality.
  *
  * @group paragraphs_library
  */
-class ParagraphsLibraryItemTest extends ParagraphsExperimentalTestBase {
-
-  use FieldUiTestTrait;
+class ParagraphsLibraryTest extends ParagraphsExperimentalTestBase {
 
   /**
    * Modules to enable.
@@ -38,7 +35,7 @@ protected function setUp() {
    */
   public function testLibraryItems() {
     // Set default theme.
-    \Drupal::service('theme_handler')->install(['bartik']);
+    \Drupal::service('theme_installer')->install(['bartik']);
     $this->config('system.theme')->set('default', 'bartik')->save();
     $this->loginAsAdmin(['create paragraphed_test content', 'edit any paragraphed_test content', 'administer paragraphs library']);
 
@@ -50,7 +47,7 @@ public function testLibraryItems() {
     // Add a new library item.
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more');
     $edit = [
       'label[0][value]' => 're usable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 're_usable_text',
@@ -78,17 +75,17 @@ public function testLibraryItems() {
     $this->assertText('Used', 'Usage column is available.');
     $this->assertText('Changed', 'Changed column is available.');
     $result = $this->cssSelect('.views-field-count');
-    $this->assertEqual(trim($result[1]->__toString()), '0', 'Usage info is correctly displayed.');
+    $this->assertEqual(trim($result[1]->getText()), '0', 'Usage info is correctly displayed.');
     $this->assertText('Delete');
     // Check the changed field.
     $result = $this->cssSelect('.views-field-changed');
-    $this->assertNotNull(trim($result[1]->__toString()));
+    $this->assertNotNull(trim($result[1]->getText()));
     $this->clickLink('Edit');
     $this->assertFieldByName('label[0][value]', 're usable paragraph label');
     $this->assertFieldByName('paragraphs[0][subform][field_text][0][value]', 're_usable_text');
 
     // Create a node with the library paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)'
@@ -97,12 +94,12 @@ public function testLibraryItems() {
 
     $library_items = \Drupal::entityTypeManager()->getStorage('paragraphs_library_item')->loadByProperties(['label' => 're usable paragraph label']);
     $this->drupalGet('admin/content/paragraphs/' . current($library_items)->id() . '/edit');
-    $this->assertText('Library item is used 1 time.');
+    $this->assertText('Modifications on this form will affect all existing usages of this entity.');
     $this->assertText('Delete');
 
     $this->drupalGet('admin/content/paragraphs');
     $result = $this->cssSelect('.views-field-count');
-    $this->assertEqual(trim($result[1]->__toString()), '1', 'Usage info is correctly displayed.');
+    $this->assertEqual(trim($result[1]->getText()), '1', 'Usage info is correctly displayed.');
 
     // Assert that the paragraph is shown correctly.
     $node_one = $this->getNodeByTitle('library_test');
@@ -110,7 +107,7 @@ public function testLibraryItems() {
     $this->assertText('re_usable_text');
 
     // Create a new node with the library paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test_new',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)'
@@ -125,7 +122,7 @@ public function testLibraryItems() {
     $this->assertNoText('Paragraphs', 'Label from library item field paragraphs is hidden.');
 
     $this->drupalGet('node/' . $node_two->id() . '/edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test_new',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)',
@@ -134,21 +131,21 @@ public function testLibraryItems() {
     $this->drupalPostForm(NULL, $edit, 'Save');
 
     $reusable_paragraphs_text = $this->xpath('//div[contains(@class, "field--name-field-paragraphs")]/div[@class="field__items"]/div[1]//div[@class="field__item"]/p');
-    $this->assertEqual($reusable_paragraphs_text[0], 're_usable_text');
+    $this->assertEqual($reusable_paragraphs_text[0]->getText(), 're_usable_text');
 
     $second_reusable_paragraphs_text = $this->xpath('//div[contains(@class, "field--name-field-paragraphs")]/div[@class="field__items"]/div[2]//div[@class="field__item"]/p');
-    $this->assertEqual($second_reusable_paragraphs_text[0], 're_usable_text');
+    $this->assertEqual($second_reusable_paragraphs_text[0]->getText(), 're_usable_text');
 
     // Edit the paragraph and change the text.
     $this->drupalGet('admin/content/paragraphs');
 
     $this->assertText('Used', 'Usage column is available.');
     $result = $this->cssSelect('.views-field-count');
-    $this->assertEqual(trim($result[1]->__toString()), '4', 'Usage info is correctly displayed.');
+    $this->assertEqual(trim($result[1]->getText()), '4', 'Usage info is correctly displayed.');
     $this->assertNoLink('4', 'Link to usage statistics is not available for user without permission.');
 
     $this->clickLink('Edit');
-    $this->assertText('Library item is used 3 times.');
+    $this->assertText('Modifications on this form will affect all existing usages of this entity.');
     $edit = [
       'paragraphs[0][subform][field_text][0][value]' => 're_usable_text_new',
     ];
@@ -199,15 +196,14 @@ public function testLibraryItems() {
     $this->assertLink('4', 0, 'Link to usage statistics is available for user with permission.');
 
     $element = $this->cssSelect('th.views-field-paragraphs__target-id');
-    $this->assertEqual($element[0]->__toString(), 'Paragraphs', 'Paragraphs column is available.');
+    $this->assertEqual($element[0]->getText(), 'Paragraphs', 'Paragraphs column is available.');
 
-    $element = $this->cssSelect('.paragraphs-collapsed-description');
-    $this->assertEqual(trim($element[0]->__toString()), 're_usable_text_new', 'Paragraphs summary available.');
+    $element = $this->cssSelect('.paragraphs-description .paragraphs-content-wrapper .summary-content');
+    $this->assertEqual(trim($element[0]->getText()), 're_usable_text_new', 'Paragraphs summary available.');
 
     // Check that the deletion of library items does not cause errors.
     current($library_items)->delete();
     $this->drupalGet('node/' . $node_one->id());
-    $this->assertNoErrorsLogged();
 
     // Test paragraphs library item field UI.
     $this->loginAsAdmin([
@@ -225,7 +221,6 @@ public function testLibraryItems() {
     $this->clickLink('Manage fields');
     $this->clickLink(t('Add field'));
     $this->assertResponse(200);
-    $this->assertNoErrorsLogged();
     $this->assertNoText('plugin does not exist');
     $this->drupalGet('admin/config/content');
     $this->clickLink('Paragraphs library item settings');
@@ -249,7 +244,7 @@ public function testConvertLibraryItemIntoParagraph() {
     // Add a new library item.
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'reusable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 'reusable_text',
@@ -258,7 +253,7 @@ public function testConvertLibraryItemIntoParagraph() {
     $this->assertText('Paragraph reusable paragraph label has been created.');
 
     // Add created library item to a node.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'Node with converted library item',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label',
@@ -269,7 +264,7 @@ public function testConvertLibraryItemIntoParagraph() {
 
     // Convert library item to paragraph.
     $this->clickLink('Edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_unlink_from_library');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_unlink_from_library');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]');
     $this->assertNoFieldByName('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]');
     $this->assertText('reusable_text');
@@ -329,7 +324,7 @@ public function testConvertParagraphIntoLibrary() {
     $edit = [
       'field_paragraphs[0][subform][field_text][0][value]' => 'Random text for testing converting into library.',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
     $this->assertText('From library');
     $this->assertText('Reusable paragraph');
     $this->assertFieldByName('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]', 'text: Random text for testing converting into library. (1)');
@@ -352,7 +347,7 @@ public function testConvertParagraphIntoLibrary() {
     $this->drupalPostForm(NULL, $edit, 'Save');
     $node = $this->getNodeByTitle('NodeTitle');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
     user_role_grant_permissions($user_role, ['administer paragraphs library']);
     $this->drupalGet('/admin/content/paragraphs');
     $this->assertText('Text');
@@ -397,14 +392,25 @@ public function testLibraryItemParagraphsSummary() {
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->drupalPostAjaxForm('admin/content/paragraphs/add/default', [], 'paragraphs_nested_test_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_subform_field_paragraphs_text_add_more');
+    $this->drupalPostForm('admin/content/paragraphs/add/default', [], 'paragraphs_nested_test_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_0_subform_field_paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'Test nested',
       'paragraphs[0][subform][field_paragraphs][0][subform][field_text][0][value]' => 'test text paragraph',
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('test text paragraph');
+
+    // Assert that the user with the access content permission can see the
+    // paragraph type label.
+    $user = $this->drupalCreateUser([
+      'access content',
+      'administer paragraphs library'
+    ]);
+    $this->drupalLogin($user);
+    $this->drupalGet('admin/content/paragraphs');
+    $paragraph_type = $this->xpath('//table/tbody/tr/td[2]');
+    $this->assertEqual(trim(strip_tags($paragraph_type[0]->getText())), 'nested_test');
   }
 
   /**
@@ -436,7 +442,7 @@ public function testLibraryitemValidation() {
 
     // Check the paragraph validation.
     $this->assertText('Paragraphs field is required.');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more');
     $edit['paragraphs[0][subform][field_text][0][value]'] = 're_usable_text';
 
     // Check that the library item is created.
@@ -466,7 +472,7 @@ public function testLibraryReferencingParagraphValidation() {
     // Add a library item with paragraphs type "Text".
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'reusable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 'reusable_text',
@@ -477,7 +483,7 @@ public function testLibraryReferencingParagraphValidation() {
     // Create a node with a "From library" paragraph referencing the library
     // item.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_from_library_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label',
@@ -526,8 +532,8 @@ public function testLibraryItemRevisions() {
 
     // Add nested paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'Test revisions nested original',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'Example text for revision original.',
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
index 19ce3705d1..0250273503 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
@@ -3,18 +3,17 @@
 namespace Drupal\Tests\paragraphs_library\FunctionalJavascript;
 
 use Behat\Mink\Element\Element;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
-use Drupal\workflows\Entity\Workflow;
 
 /**
  * Tests Paragraphs, Paragraphs Library and Content Moderation integration.
  *
  * @group paragraphs_library
  */
-class ParagraphsContentModerationTest extends JavascriptTestBase {
+class ParagraphsContentModerationTest extends WebDriverTestBase {
 
   use ParagraphsTestBaseTrait, FieldUiTestTrait, ParagraphsLastEntityQueryTrait;
 
@@ -51,6 +50,11 @@ class ParagraphsContentModerationTest extends JavascriptTestBase {
     'content_moderation',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'classy';
+
   /**
    * {@inheritdoc}
    */
@@ -193,6 +197,8 @@ public function testModeratedParagraphedContent() {
     $this->assertNotNull($textfield);
     $page->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2');
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->clickLink('Revision information');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Node revision #2 - This is a special version!');
     $page->pressButton('Save');
     $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 2) has been updated.');
@@ -220,6 +226,7 @@ public function testModeratedParagraphedContent() {
     $this->assertNotNull($textfield);
     $page->fillField('field_paragraphs[2][subform][field_text][0][value]', 'Direct paragraph text 3');
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Node revision #3');
     $page->pressButton('Save');
     $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 3) has been updated.');
@@ -259,6 +266,7 @@ public function testModeratedParagraphedContent() {
     $paragraph3_confirm_remove_button->press();
     $assert_session->assertWaitOnAjaxRequest();
     $page->selectFieldOption('moderation_state[0][state]', 'draft');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Node revision #4');
     $page->pressButton('Save');
     // The admin is currently at /node/*/latest.
@@ -360,6 +368,7 @@ public function testModeratedParagraphedContent() {
     $this->drupalGet("/node/$host_node_id/edit");
     $page->fillField('title[0][value]', 'Host page 1 (rev 6)');
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Node revision #6');
     $page->pressButton('Save');
     $assert_session->pageTextContains('paragraphed_moderated_test Host page 1 (rev 6) has been updated.');
@@ -442,6 +451,7 @@ public function testModeratedContentNestedParagraphs() {
     $page->fillField('paragraphs[0][subform][field_text][0][value]', 'This is the low-level text.');
     // This is published initially.
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Child initial revision.');
     $page->pressButton('Save');
     $assert_session->pageTextContains('Paragraph Child library item has been created.');
@@ -462,6 +472,7 @@ public function testModeratedContentNestedParagraphs() {
     $page->fillField('paragraphs[0][subform][field_nested_paragraphs][0][target_id]', "Child library item ($child_library_item_id)");
     // Let's make this initially a draft.
     $page->selectFieldOption('moderation_state[0][state]', 'draft');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Rich item initial revision.');
     $page->pressButton('Save');
     $assert_session->pageTextContains('Paragraph Rich library item has been created.');
@@ -483,7 +494,7 @@ public function testModeratedContentNestedParagraphs() {
     $assert_session->pageTextContains('Rich library item');
     $table = $assert_session->elementExists('css', 'table.views-table');
     $rich_item_row = $this->getTableRowWithText($table, 'Rich library item');
-    $rich_item_checkbox = $assert_session->elementExists('css', 'input[type="checkbox"]', $rich_item_row);
+    $rich_item_checkbox = $assert_session->elementExists('css', 'input[type="radio"]', $rich_item_row);
     $rich_item_checkbox->click();
     $page->pressButton('Select reusable paragraph');
     $session->wait(1000);
@@ -491,6 +502,7 @@ public function testModeratedContentNestedParagraphs() {
     $assert_session->assertWaitOnAjaxRequest();
     // Save the node as published.
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Node initial revision');
     $page->pressButton('Save');
 
@@ -507,6 +519,7 @@ public function testModeratedContentNestedParagraphs() {
     $this->drupalGet("/admin/content/paragraphs/{$rich_library_item_id}/edit");
     $page->fillField('paragraphs[0][subform][field_intermediate_text][0][value]', 'First level text - published');
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Rich item first published revision.');
     $page->pressButton('Save');
     $assert_session->pageTextContains('Paragraph Rich library item has been updated.');
@@ -520,6 +533,7 @@ public function testModeratedContentNestedParagraphs() {
     $this->drupalGet("/admin/content/paragraphs/{$child_library_item_id}/edit");
     $page->fillField('paragraphs[0][subform][field_text][0][value]', 'The low-level text has been modified (pending approval).');
     $page->selectFieldOption('moderation_state[0][state]', 'draft');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Child item unapproved changes.');
     $page->pressButton('Save');
     $assert_session->pageTextContains('Paragraph Child library item has been updated.');
@@ -534,6 +548,7 @@ public function testModeratedContentNestedParagraphs() {
     $this->drupalGet("/admin/content/paragraphs/{$child_library_item_id}/edit");
     $page->fillField('paragraphs[0][subform][field_text][0][value]', 'The low-level text has been modified (approved!).');
     $page->selectFieldOption('moderation_state[0][state]', 'published');
+    $page->find('css', 'a[href="#edit-revision-information"]')->click();
     $page->fillField('revision_log[0][value]', 'Child item approved changes.');
     $page->pressButton('Save');
     $assert_session->pageTextContains('Paragraph Child library item has been updated.');
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
index 4405e17cbe..4247f71d6d 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
@@ -3,7 +3,7 @@
 namespace Drupal\Tests\paragraphs_library\FunctionalJavascript;
 
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\Tests\entity_browser\FunctionalJavascript\EntityBrowserJavascriptTestBase;
+use Drupal\Tests\entity_browser\FunctionalJavascript\EntityBrowserWebDriverTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
 /**
@@ -11,7 +11,7 @@
  *
  * @group paragraphs_library
  */
-class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserJavascriptTestBase {
+class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserWebDriverTestBase {
 
   use ParagraphsTestBaseTrait;
 
@@ -34,6 +34,11 @@ class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserJavascriptTest
     'content_translation'
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'classy';
+
   /**
    * Tests a flow of adding/removing references with paragraphs.
    */
@@ -87,7 +92,8 @@ public function testEntityBrowserWidget() {
     $this->waitForAjaxToFinish();
     $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items');
     $this->waitForAjaxToFinish();
-    $this->getSession()->getPage()->checkField('edit-entity-browser-select-paragraphs-library-item1');
+    $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:1"].form-radio');
+    $style_selector->click();
     $this->getSession()->switchToIFrame();
 
     $drop = <<<JS
@@ -128,6 +134,90 @@ public function testEntityBrowserWidget() {
     // Check that there is only one translation of the paragraph listed.
     $rows = $this->xpath('//*[@id="entity-browser-paragraphs-library-items-form"]/div[1]/div[2]/table/tbody/tr');
     $this->assertTrue(count($rows) == 1);
+
+    // Add a text paragraph in a new library item.
+    $this->drupalGet('admin/content/paragraphs/add/default');
+    $element = $this->getSession()->getPage()->find('xpath', '//*[contains(@class, "dropbutton-toggle")]');
+    $element->click();
+    $button = $this->getSession()->getPage()->findButton('Add text');
+    $button->press();
+    $this->waitForAjaxToFinish();
+    $this->getSession()->getPage()->fillField('label[0][value]', 'Inner library item');
+    $this->getSession()->getPage()->fillField('paragraphs[0][subform][field_text][0][value]', 'This is a reusable text.');
+    $this->submitForm([], 'Save');
+    // Add a library item inside a library item.
+    $this->drupalGet('admin/content/paragraphs/add/default');
+    $this->getSession()->getPage()->fillField('label[0][value]', 'Outside library item');
+    $button = $this->getSession()->getPage()->findButton('Add From library');
+    $button->press();
+    $this->waitForAjaxToFinish();
+    $this->getSession()->getPage()->pressButton('Select reusable paragraph');
+    $this->waitForAjaxToFinish();
+    $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items');
+    $this->waitForAjaxToFinish();
+    $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:2"].form-radio');
+    $style_selector->click();
+    $this->getSession()->switchToIFrame();
+    $drop = <<<JS
+    jQuery('input[type=submit][value="Select reusable paragraph"]', window.frames['entity_browser_iframe_paragraphs_library_items'].document).trigger('click')
+JS;
+    $this->getSession()->evaluateScript($drop);
+    sleep(1);
+    $this->waitForAjaxToFinish();
+    // Edit the inside library item after adding it.
+    $this->getSession()->getPage()->pressButton('Edit');
+    $this->waitForAjaxToFinish();
+    $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]');
+    $this->getSession()->getPage()->fillField('paragraphs[0][subform][field_text][0][value]', 'This is a reusable text UPDATED.');
+    $save_button = $this->assertSession()->elementExists('css', '.ui-dialog .ui-dialog-buttonset button');
+    $save_button->press();
+    $this->waitForAjaxToFinish();
+    $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'This is a reusable text UPDATED.');
+    $this->submitForm([], 'Save');
+    // Edit the outside library item.
+    $this->getSession()->getPage()->clickLink('Outside library item');
+    $this->getSession()->getPage()->clickLink('Edit');
+    $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'This is a reusable text UPDATED.');
+    // Edit the inner library item and assert the fields and values.
+    $this->getSession()->getPage()->pressButton('Edit');
+    $this->waitForAjaxToFinish();
+    $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]');
+
+    // Add a node with the outside library item.
+    $this->drupalGet('node/add');
+    $title = $this->assertSession()->fieldExists('Title');
+    $title->setValue('Overlay node');
+    $this->getSession()->getPage()->pressButton('Add From library');
+    $this->waitForAjaxToFinish();
+    $this->getSession()->getPage()->pressButton('Select reusable paragraph');
+    $this->waitForAjaxToFinish();
+    $this->getSession()->switchToIFrame('entity_browser_iframe_paragraphs_library_items');
+    $this->waitForAjaxToFinish();
+    $style_selector = $this->getSession()->getPage()->find('css', 'input[value="paragraphs_library_item:3"].form-radio');
+    $this->assertTrue($style_selector->isVisible());
+    $style_selector->click();
+    $this->getSession()->switchToIFrame();
+    $drop = <<<JS
+    jQuery('input[type=submit][value="Select reusable paragraph"]', window.frames['entity_browser_iframe_paragraphs_library_items'].document).trigger('click')
+JS;
+    $this->getSession()->evaluateScript($drop);
+    sleep(1);
+    $this->waitForAjaxToFinish();
+    $this->assertSession()->elementContains('css', '.paragraphs-collapsed-description .paragraphs-content-wrapper', 'Inner library item');
+    $this->submitForm([], 'Save');
+    $this->assertSession()->pageTextContains('paragraphed_test Overlay node has been created.');
+    // Edit the node.
+    $node = $this->getNodeByTitle('Overlay node');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    // Edit the Outside library item.
+    $this->getSession()->getPage()->pressButton('Edit');
+    $this->waitForAjaxToFinish();
+    // Edit the inner library item and assert its fields.
+    $modal_form = $this->getSession()->getPage()->find('css', '.ui-dialog .paragraphs-library-item-form');
+    $save_button = $modal_form->find('css', '.edit-button');
+    $save_button->press();
+    $this->waitForAjaxToFinish();
+    $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]');
   }
 
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
index 340e188bd4..d80c46fa7e 100644
--- a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
@@ -1,14 +1,13 @@
 name: Paragraphs Type Permissions
 type: module
 description: 'Allows users to configure permissions for individual Paragraphs types.'
-# core: 8.x
+core_version_requirement: ^8.7.7 || ^9
 package: Paragraphs
 
 dependencies:
   - paragraphs:paragraphs
 
-# Information added by Drupal.org packaging script on 2019-02-20
-version: '8.x-1.6'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-02-16
+version: '8.x-1.11'
 project: 'paragraphs'
-datestamp: 1550669588
+datestamp: 1581850832
diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php b/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php
index da3ba5f1ff..b18f9a271e 100644
--- a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php
+++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/src/ParagraphsTypePermissions.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\paragraphs_type_permissions;
 
-use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -12,7 +11,6 @@
 class ParagraphsTypePermissions {
 
   use StringTranslationTrait;
-  use UrlGeneratorTrait;
 
   /**
    * Returns an array of content permissions.
diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
similarity index 86%
rename from web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php
rename to web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
index 744af69503..a784efe1c7 100644
--- a/web/modules/paragraphs/modules/paragraphs_type_permissions/src/Tests/ParagraphsTypePermissionsTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
@@ -1,12 +1,12 @@
 <?php
 
-namespace Drupal\paragraphs_type_permissions\Tests;
+namespace Drupal\Tests\paragraphs_type_permissions\Functional;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 use Drupal\user\Entity\Role;
 
 /**
@@ -14,16 +14,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsTypePermissionsTest extends WebTestBase {
+class ParagraphsTypePermissionsTest extends BrowserTestBase {
 
   use FieldUiTestTrait, ParagraphsCoreVersionUiTestTrait, ParagraphsTestBaseTrait;
 
   /**
-   * Modules to enable.
-   *
-   * @var array
+   * {@inheritdoc}
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'image',
     'field',
@@ -34,6 +32,11 @@ class ParagraphsTypePermissionsTest extends WebTestBase {
     'paragraphs_type_permissions',
   );
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -140,11 +143,11 @@ public function testAnonymousParagraphsTypePermissions() {
     $this->drupalPostForm(NULL, NULL, t('Add images'));
     $this->drupalPostForm(NULL, NULL, t('Add text'));
 
-    $image_text = $this->drupalGetTestFiles('image')[0];
+    $image_text = $this->getTestFiles('image')[0];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_0_subform_field_image_demo_0]' => $image_text->uri,
     ], t('Upload'));
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -190,7 +193,7 @@ public function testAnonymousParagraphsTypePermissions() {
 
     // Set edit mode to open.
     $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display');
-    $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_demo_settings_edit");
+    $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit");
     $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
@@ -253,6 +256,17 @@ public function testAnonymousParagraphsTypePermissions() {
     $this->assertText('Published');
     $this->assertText('Images');
     $this->assertText('You are not allowed to edit or remove this Paragraph.');
+    $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">image-test_0.png<');
+    $this->assertNoRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Paragraph type Text<');
+
+    // Check that the paragraph is collapsed by asserting the content summary.
+    $authenticated_role->grantPermission('view paragraph content text');
+    $authenticated_role->save();
+    $this->drupalLogin($authenticated_user);
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertText('You are not allowed to edit or remove this Paragraph.');
+    $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">image-test_0.png<');
+    $this->assertRaw('paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Paragraph type Text<');
   }
 
 }
diff --git a/web/modules/paragraphs/paragraphs.info.yml b/web/modules/paragraphs/paragraphs.info.yml
index 8bfdcd5737..6b54227d94 100644
--- a/web/modules/paragraphs/paragraphs.info.yml
+++ b/web/modules/paragraphs/paragraphs.info.yml
@@ -1,14 +1,14 @@
 name: Paragraphs
 type: module
 description: 'Enables the creation of paragraphs entities.'
-# core: 8.x
+core_version_requirement: ^8.7.7 || ^9
 package: Paragraphs
 configure: entity.paragraphs_type.collection
 
 dependencies:
   - entity_reference_revisions:entity_reference_revisions
   - drupal:file
-  - 'drupal:system (>= 8.5)'
+
 test_dependencies:
   - diff:diff
   - replicate:replicate
@@ -16,8 +16,7 @@ test_dependencies:
   - field_group:field_group
   - block_field:block_field
 
-# Information added by Drupal.org packaging script on 2019-02-20
-version: '8.x-1.6'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-02-16
+version: '8.x-1.11'
 project: 'paragraphs'
-datestamp: 1550669588
+datestamp: 1581850832
diff --git a/web/modules/paragraphs/paragraphs.install b/web/modules/paragraphs/paragraphs.install
index 927c7350aa..49bb4541b7 100644
--- a/web/modules/paragraphs/paragraphs.install
+++ b/web/modules/paragraphs/paragraphs.install
@@ -91,7 +91,6 @@ function paragraphs_update_8004() {
     }
   }
 
-
   // Delete the storage definition if it was defined before.
   $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field_name, 'paragraph');
   if ($storage_definition) {
@@ -220,6 +219,17 @@ function paragraphs_update_8012() {
 function paragraphs_update_8013() {
   $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
   $entity_type = $definition_update_manager->getEntityType('paragraph');
+
+  // Update the revision metadata keys to remove revision uid which is removed
+  // in 8017 and 8021.
+  if ($metadata_keys = $entity_type->get('revision_metadata_keys')) {
+    if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) {
+      unset($metadata_keys['revision_user']);
+      $metadata_keys['revision_default'] = 'revision_default';
+      $entity_type->set('revision_metadata_keys', $metadata_keys);
+    }
+  }
+
   $keys = $entity_type->getKeys();
   $keys['published'] = 'status';
   $entity_type->set('entity_keys', $keys);
@@ -256,3 +266,201 @@ function paragraphs_update_8015() {
     }
   }
 }
+
+/**
+ * Remove the uid and revision_uid fields.
+ */
+function paragraphs_update_8016() {
+  $database = \Drupal::database();
+
+  $spec = array(
+    'type' => 'varchar',
+    'description' => "Revision UID",
+    'length' => 20,
+    'not null' => FALSE,
+  );
+
+  $schema = $database->schema();
+
+  if (!$schema->fieldExists('paragraphs_item_field_data', 'revision_uid')) {
+    $schema->addField('paragraphs_item_field_data', 'revision_uid', $spec);
+  }
+
+  if (!$schema->fieldExists('paragraphs_item_revision_field_data', 'revision_uid')) {
+    $schema->addField('paragraphs_item_revision_field_data', 'revision_uid', $spec);
+  }
+
+  $tables_fields = [
+    'paragraphs_item_revision' => 'revision_uid',
+    'paragraphs_item_field_data' => 'uid',
+    'paragraphs_item_revision_field_data' => 'uid',
+  ];
+
+  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+
+  foreach ($tables_fields as $table => $field) {
+    if ($database->schema()->fieldExists($table, $field)) {
+      $database->update($table)
+        ->fields([$field => NULL])
+        ->execute();
+    }
+  }
+
+  foreach (array_unique($tables_fields) as $table => $field) {
+    $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field, 'paragraph');
+    if ($storage_definition) {
+      $entity_definition_update_manager->uninstallFieldStorageDefinition($storage_definition);
+    }
+  }
+}
+
+/**
+ * Moved function content to paragraphs_update_8023().
+ * see https://www.drupal.org/project/paragraphs/issues/2833935#comment-13471948
+ */
+function paragraphs_update_8017() {
+
+}
+
+/**
+ * Make the parent fields revisionable.
+ */
+function paragraphs_update_8018(&$sandbox) {
+  $database = \Drupal::database();
+  // Initialize some variables during the first pass through.
+  if (!isset($sandbox['total'])) {
+    // Add the parent fields to the revision data table.
+    foreach (['parent_id', 'parent_type', 'parent_field_name'] as $field_name) {
+      $column_schema = [
+        'type' => 'varchar_ascii',
+        'length' => $field_name == 'parent_id' ? 255 : 32,
+        'binary' => FALSE,
+        'not null' => FALSE,
+      ];
+      // Create fields if they don't already exist.
+      if (!$database->schema()->fieldExists('paragraphs_item_revision_field_data', $field_name)) {
+        $database->schema()
+          ->addField('paragraphs_item_revision_field_data', $field_name, $column_schema);
+      }
+    }
+
+    // Get all paragraphs to update.
+    $paragraphs = \Drupal::database()->select('paragraphs_item_field_data', 'p')
+      ->countQuery()
+      ->execute()
+      ->fetchField(0);
+    $sandbox['total'] = $paragraphs;
+    $sandbox['current'] = 0;
+  }
+
+  // Do not continue if no paragraphs are found.
+  if (empty($sandbox['total'])) {
+    $sandbox['#finished'] = 1;
+    return t('No Paragraphs to be processed.');
+  }
+
+  $paragraphs_per_batch = 50;
+
+  $query = $database->select('paragraphs_item_field_data', 'p');
+  $query->fields('p', ['id', 'parent_id', 'parent_type', 'parent_field_name']);
+  $query->range($sandbox['current'], $paragraphs_per_batch);
+  $result = $query->execute();
+
+  foreach ($result as $row) {
+    $database->update('paragraphs_item_revision_field_data')
+      ->fields([
+        'parent_id' => $row->parent_id,
+        'parent_type' => $row->parent_type,
+        'parent_field_name' => $row->parent_field_name,
+      ])
+      ->condition('id', $row->id)
+      ->execute();
+    $sandbox['current']++;
+  }
+  $sandbox['#finished'] = ($sandbox['current'] / $sandbox['total']);
+  return t('@count Paragraphs processed.', ['@count' => $sandbox['current']]);
+}
+
+/**
+ * Update the field storage definitions of the parent fields.
+ */
+function paragraphs_update_8019() {
+  \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $last_installed_schema = \Drupal::service('entity.last_installed_schema.repository');
+  foreach (['parent_id', 'parent_type', 'parent_field_name'] as $field_name) {
+    $column_schema = [
+      'type' => 'varchar_ascii',
+      'length' => $field_name == 'parent_id' ? 255 : 32,
+      'binary' => FALSE,
+      'not null' => FALSE,
+    ];
+    // Update the field storage repository.
+    $storage_definition = $definition_update_manager->getFieldStorageDefinition($field_name, 'paragraph');
+    $storage_definition->setRevisionable(TRUE);
+    $last_installed_schema->setLastInstalledFieldStorageDefinition($storage_definition);
+
+    // Update the stored field schema.
+    // @todo: There has to be a better way to do this.
+    $key = 'paragraph.field_schema_data.' . $field_name;
+    $field_schema = \Drupal::keyValue('entity.storage_schema.sql')->get($key);
+    $field_schema['paragraphs_item_revision_field_data']['fields'][$field_name] = $column_schema;
+    \Drupal::keyValue('entity.storage_schema.sql')->set($key, $field_schema);
+  }
+}
+
+/**
+ * Remove the base field overrides for uid & revision_uid.
+ */
+function paragraphs_update_8020() {
+  $config_factory = \Drupal::configFactory();
+  $names = $config_factory->listAll('core.base_field_override.paragraph.');
+  foreach ($names as $name) {
+    $config = $config_factory->getEditable($name);
+    if (in_array($config->get('field_name'), ['uid', 'revision_uid'])) {
+      $config->delete();
+    }
+  }
+}
+
+/**
+ * Update the revision metadata keys to remove revision uid (fixes 8017).
+ */
+function paragraphs_update_8021() {
+  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $entity_type = $entity_definition_update_manager->getEntityType('paragraph');
+  if ($metadata_keys = $entity_type->get('revision_metadata_keys')) {
+    if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) {
+      unset($metadata_keys['revision_user']);
+      $metadata_keys['revision_default'] = 'revision_default';
+      $entity_type->set('revision_metadata_keys', $metadata_keys);
+      $entity_definition_update_manager->updateEntityType($entity_type);
+    }
+  }
+}
+
+/**
+ * Ensure that the parent indexes are added to the revision data table.
+ */
+function paragraphs_update_8022() {
+  $manager = \Drupal::entityDefinitionUpdateManager();
+
+  // Regenerate entity type indexes.
+  $manager->updateEntityType($manager->getEntityType('paragraph'));
+}
+
+/**
+ * Update the revision metadata keys to remove revision uid.
+ */
+function paragraphs_update_8023() {
+  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $entity_type = $entity_definition_update_manager->getEntityType('paragraph');
+  if ($metadata_keys = $entity_type->get('revision_metadata_keys')) {
+    if (is_array($metadata_keys) && isset($metadata_keys['revision_user'])) {
+      unset($metadata_keys['revision_user']);
+      $metadata_keys['revision_default'] = 'revision_default';
+      $entity_type->set('revision_metadata_keys', $metadata_keys);
+      $entity_definition_update_manager->updateEntityType($entity_type);
+    }
+  }
+}
diff --git a/web/modules/paragraphs/paragraphs.libraries.yml b/web/modules/paragraphs/paragraphs.libraries.yml
index 28e81165e6..42f4733efa 100644
--- a/web/modules/paragraphs/paragraphs.libraries.yml
+++ b/web/modules/paragraphs/paragraphs.libraries.yml
@@ -1,12 +1,12 @@
 drupal.paragraphs.admin:
   dependencies:
-      - core/jquery
-      - core/drupal
-      - core/drupalSettings
-      - core/jquery.once
-      - core/jquery.form
-      - core/drupal.ajax
-      - core/drupal.dropbutton
+    - core/jquery
+    - core/drupal
+    - core/drupalSettings
+    - core/jquery.once
+    - core/jquery.form
+    - core/drupal.ajax
+    - core/drupal.dropbutton
   css:
     theme:
       css/paragraphs.admin.css: {}
@@ -68,10 +68,12 @@ drupal.paragraphs.modal:
     theme:
       css/paragraphs.modal.css: {}
   dependencies:
+    - core/drupal.dialog
     - core/drupal.dialog.ajax
     - core/jquery.once
-    - core/jquery.ui.tabs
 
+# This library will be deleted in paragraphs_library_info_alter when
+# core/sortable is available.
 sortable:
   website: https://github.com/RubaXa/Sortable
   license:
@@ -89,7 +91,10 @@ paragraphs-dragdrop:
   dependencies:
     - core/jquery
     - core/drupal
-    - paragraphs/sortable
+    # Sortable is only in core from 8.8+. When the library is not available, the
+    # dependency will be changed with paragraphs/sortable in
+    # paragraphs_library_info_alter.
+    - core/sortable
 
 drupal.paragraphs.formatter:
   css:
diff --git a/web/modules/paragraphs/paragraphs.module b/web/modules/paragraphs/paragraphs.module
index 014a7a3bbc..20aacf17a0 100644
--- a/web/modules/paragraphs/paragraphs.module
+++ b/web/modules/paragraphs/paragraphs.module
@@ -15,6 +15,7 @@
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\paragraphs\Plugin\migrate\field\FieldCollection;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Entity\EntityTypeInterface;
 
 /**
  * Implements hook_help().
@@ -77,6 +78,10 @@ function paragraphs_theme() {
       'render element' => 'element',
       'template' => 'paragraphs-actions',
     ],
+    'paragraphs_summary' => [
+      'render element' => 'element',
+      'template' => 'paragraphs-summary',
+    ],
   );
 }
 
@@ -357,7 +362,7 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) {
     }
 
     // Add the paragraph type as a class to every row.
-    if (isset($variables['element'][0]['#paragraph_type'])) {
+    if (isset($variables['element']['#paragraphs_widget'])) {
       foreach ($variables['table']['#rows'] as $key => $row) {
         if (isset($row['data'][1]['data']['#paragraph_type'])) {
           $variables['table']['#rows'][$key]['class'][] = 'paragraph-type--' . str_replace('_', '-', $row['data'][1]['data']['#paragraph_type']);
@@ -390,6 +395,11 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) {
  * Implements hook_libraries_info().
  */
 function paragraphs_libraries_info() {
+  // Drupal 8.8+ has the sortable library in core, so we don't need to provide custom library information here.
+  if (version_compare(\Drupal::VERSION, '8.8', '>=')) {
+    return [];
+  }
+
   $libraries = [
     'Sortable' => [
       'name' => 'Sortable',
@@ -421,6 +431,18 @@ function paragraphs_library_info_alter(&$libraries, $extension) {
     return;
   }
 
+  if (version_compare(\Drupal::VERSION, '8.8', '>=')) {
+    // When core/sortable is available, the paragraphs/sortable library can be removed.
+    unset($libraries['sortable']);
+    return $libraries;
+  }
+  else {
+    // If the core/sortable is not available, the paragraphs/sortable library should be used as a dependency of
+    // paragraphs-dragdrop instead.
+    $library_core_dep_key = array_search('core/sortable', $libraries['paragraphs-dragdrop']['dependencies']);
+    $libraries['paragraphs-dragdrop']['dependencies'][$library_core_dep_key] = 'paragraphs/sortable';
+  }
+
   if (\Drupal::moduleHandler()->moduleExists('libraries')) {
     $info = libraries_detect('Sortable');
   }
@@ -473,16 +495,16 @@ function paragraphs_library_info_alter(&$libraries, $extension) {
  * https://www.drupal.org/project/drupal/issues/2904765 is resolved
  */
 function paragraphs_migration_plugins_alter(array &$migrations) {
+  /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */
+  $migration_plugin_manager = \Drupal::service('plugin.manager.migration');
+  /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */
+  $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source');
+
   foreach ($migrations as $key => &$migration) {
-    /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */
-    $migration_plugin_manager = \Drupal::service('plugin.manager.migration');
-    $migration_stub = $migration_plugin_manager->createStubMigration($migration);
-    /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */
-    $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source');
-    $source = NULL;
-    $configuration = $migration['source'];
-    $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub);
-    if ($source) {
+    if (!empty($migration['source'])) {
+      $configuration = $migration['source'];
+      $migration_stub = $migration_plugin_manager->createStubMigration($migration);
+      $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub);
       if (is_a($migration['class'], FieldMigration::class, TRUE)) {
 
         // Field storage.
@@ -516,6 +538,17 @@ function paragraphs_entity_type_alter(array &$entity_types) {
   $entity_types['paragraph']->setHandlerClass('moderation', '');
 }
 
+/**
+ * Implements hook_entity_base_field_info_alter().
+ */
+function paragraphs_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
+  // Since the paragraph entity doesn't have uid fields anymore, remove the
+  // content_translation_uid from the field definitions.
+  if ($entity_type->id() == 'paragraph' && isset($fields['content_translation_uid'])) {
+    unset($fields['content_translation_uid']);
+  }
+}
+
 /**
  * Remove 'field_' prefix from field collection bundles.
  *
@@ -578,3 +611,18 @@ function _paragraphs_migration_entity_type_adjust(array &$migration, $destinatio
   ];
   $migration['process'][$destination] = $entity_type_process;
 }
+
+/**
+ * Prepares variables for.
+ *
+ * Default template: paragraphs-summary.html.twig
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - buttons: An array of buttons to display in the modal form.
+ */
+function template_preprocess_paragraphs_summary(&$variables) {
+  $variables['content'] = $variables['element']['#summary']['content'];
+  $variables['behaviors'] = $variables['element']['#summary']['behaviors'];
+  $variables['expanded'] = !empty($variables['element']['#expanded']);
+}
diff --git a/web/modules/paragraphs/paragraphs.post_update.php b/web/modules/paragraphs/paragraphs.post_update.php
index bd7d3e7354..8208016385 100644
--- a/web/modules/paragraphs/paragraphs.post_update.php
+++ b/web/modules/paragraphs/paragraphs.post_update.php
@@ -5,6 +5,10 @@
  * Post update functions for Paragraphs.
  */
 
+use Drupal\Core\Database\Query\Condition;
+use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Site\Settings;
 use Drupal\field\Entity\FieldStorageConfig;
 
@@ -110,6 +114,153 @@ function paragraphs_post_update_set_paragraphs_parent_fields(&$sandbox) {
   else {
     $sandbox['progress'] += Settings::get('paragraph_limit', 50);
   }
-  // Update #finished, 1 if the the whole update has finished.
+  // Update #finished, 1 if the whole update has finished.
   $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_paragraph_field_id'] / $sandbox['max']);
 }
+
+/**
+ * Update the parent fields with revisionable data.
+ */
+function paragraphs_post_update_rebuild_parent_fields(array &$sandbox) {
+  $database = \Drupal::database();
+  $entity_type_manager = \Drupal::entityTypeManager();
+  /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $paragraph_revisions_data_table = $entity_type_manager->getDefinition('paragraph')->getRevisionDataTable();
+  $paragraph_storage = $entity_type_manager->getStorage('paragraph');
+
+  if (!isset($sandbox['current_index'])) {
+    $entity_reference_revisions_fields = $entity_field_manager->getFieldMapByFieldType('entity_reference_revisions');
+    $paragraph_field_ids = [];
+    foreach ($entity_reference_revisions_fields as $entity_type_id => $fields) {
+      // Skip non-revisionable entity types.
+      $entity_type_definition = $entity_definition_update_manager->getEntityType($entity_type_id);
+      if (!$entity_type_definition || !$entity_type_definition->isRevisionable()) {
+        continue;
+      }
+
+      // Skip non-SQL entity storage implementations.
+      $storage = $entity_type_manager->getStorage($entity_type_id);
+      if (!$storage instanceof SqlEntityStorageInterface) {
+        continue;
+      }
+
+      $storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
+      $storage_definitions = array_intersect_key($storage_definitions, $fields);
+
+      // Process the fields that reference paragraphs.
+      $storage_definitions = array_filter($storage_definitions, function (FieldStorageDefinitionInterface $field_storage) {
+        return $field_storage->getSetting('target_type') === 'paragraph';
+      });
+
+      foreach ($storage_definitions as $field_name => $field_storage) {
+        // Get the field revision table name.
+        $table_mapping = $storage->getTableMapping();
+        $column_names = $table_mapping->getColumnNames($field_name);
+        $revision_column = $column_names['target_revision_id'];
+
+        if ($field_storage instanceof BaseFieldDefinition && $field_storage->getCardinality() === 1) {
+          $field_revision_table = $storage->getRevisionDataTable() ?: $storage->getRevisionTable();
+          $entity_id_column = $entity_type_definition->getKey('id');
+        }
+        else {
+          $field_revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage);
+          $entity_id_column = 'entity_id';
+        }
+
+        // Build a data array of the needed data to do the query.
+        $data = [
+          'entity_type_id' => $entity_type_id,
+          'field_name' => $field_name,
+          'revision_table' => $field_revision_table,
+          'entity_id_column' => $entity_id_column,
+          'revision_column' => $revision_column,
+          'langcode_column' => $entity_type_definition->getKey('langcode'),
+        ];
+
+        // Nested paragraphs must be updated first.
+        if ($entity_type_id === 'paragraph') {
+          array_unshift($paragraph_field_ids, $data);
+        }
+        else {
+          $paragraph_field_ids[] = $data;
+        }
+      }
+    }
+
+    if (empty($paragraph_field_ids)) {
+      // There are no paragraph fields. Return before initializing the sandbox.
+      return;
+    }
+
+    // Initialize the sandbox.
+    $sandbox['current_index'] = 0;
+    $sandbox['paragraph_field_ids'] = $paragraph_field_ids;
+    $sandbox['max'] = count($paragraph_field_ids);
+    $sandbox['max_revision_id'] = NULL;
+  }
+
+  $current_field = $sandbox['paragraph_field_ids'][$sandbox['current_index']];
+  $revision_column = $current_field['revision_column'];
+  $entity_id_column = $current_field['entity_id_column'];
+  $entity_type_id = $current_field['entity_type_id'];
+  $field_name = $current_field['field_name'];
+
+  // Select the field values from the revision of the parent entity type.
+  $query = $database->select($current_field['revision_table'], 'f');
+
+  // Join tables by paragraph revision IDs.
+  $query->innerJoin($paragraph_revisions_data_table, 'p', "f.$revision_column = p.revision_id");
+  $query->fields('f', [$entity_id_column, $revision_column]);
+
+  // Select paragraphs with at least one wrong parent field.
+  $or_group = new Condition('OR');
+  $or_group->where("p.parent_id <> f.$entity_id_column");
+  $or_group->condition('p.parent_type', $entity_type_id, '<>');
+  $or_group->condition('p.parent_field_name', $field_name, '<>');
+  $query->condition($or_group);
+
+  // Match the langcode so we can deal with revisions translations.
+  if (!empty($current_field['langcode_column'])) {
+    $query->where('p.langcode = f.' . $current_field['langcode_column']);
+  }
+
+  // Order the query by revision ID and limit the number of results.
+  $query->orderBy('p.revision_id');
+
+  // Only check the revisions that are not already processed.
+  if ($sandbox['max_revision_id']) {
+    $query->condition('p.revision_id', $sandbox['max_revision_id'], '>');
+  }
+  // Limit the number of processed paragraphs per run.
+  $query->range(0, Settings::get('paragraph_limit', 100));
+
+  $results = $query->execute()->fetchAll();
+
+  // Update the parent fields of the identified paragraphs revisions.
+  foreach ($results as $result) {
+    /** @var \Drupal\paragraphs\ParagraphInterface $revision */
+    $revision = $paragraph_storage->loadRevision($result->$revision_column);
+    if ($revision) {
+      $revision->set('parent_id', $result->$entity_id_column);
+      $revision->set('parent_type', $entity_type_id);
+      $revision->set('parent_field_name', $field_name);
+      $revision->save();
+    }
+  }
+
+  // Continue with the next element in case we processed all the paragraphs
+  // assigned to the current paragraph field.
+  if (count($results) < Settings::get('paragraph_limit', 100)) {
+    $sandbox['current_index']++;
+    $sandbox['max_revision_id'] = NULL;
+  }
+  else {
+    $last_revision_result = end($results);
+    $sandbox['max_revision_id'] = $last_revision_result->$revision_column;
+  }
+
+  // Update finished key if the whole update has finished.
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current_index'] / $sandbox['max']);
+}
diff --git a/web/modules/paragraphs/paragraphs.services.yml b/web/modules/paragraphs/paragraphs.services.yml
index f700392878..b8c96660c1 100644
--- a/web/modules/paragraphs/paragraphs.services.yml
+++ b/web/modules/paragraphs/paragraphs.services.yml
@@ -3,3 +3,8 @@ services:
     class: Drupal\paragraphs\ParagraphsBehaviorManager
     parent: default_plugin_manager
     arguments: ['@entity_type.manager', '@config.factory']
+  paragraphs_type.uuid_lookup:
+    class: \Drupal\paragraphs\ParagraphsTypeIconUuidLookup
+    arguments: ['@cache.bootstrap', '@lock', '@entity_type.manager']
+    tags:
+      - { name: needs_destruction }
diff --git a/web/modules/paragraphs/src/Entity/Paragraph.php b/web/modules/paragraphs/src/Entity/Paragraph.php
index ac6fc93bad..c96fac05e9 100644
--- a/web/modules/paragraphs/src/Entity/Paragraph.php
+++ b/web/modules/paragraphs/src/Entity/Paragraph.php
@@ -5,21 +5,21 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\RevisionLogEntityTrait;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\ChangedFieldItemList;
+use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Render\Markup;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\entity_reference_revisions\EntityNeedsSaveInterface;
 use Drupal\entity_reference_revisions\EntityNeedsSaveTrait;
 use Drupal\field\FieldConfigInterface;
 use Drupal\paragraphs\ParagraphInterface;
+use Drupal\user\EntityOwnerInterface;
 use Drupal\user\UserInterface;
 
 /**
@@ -30,6 +30,13 @@
  * @ContentEntityType(
  *   id = "paragraph",
  *   label = @Translation("Paragraph"),
+ *   label_collection = @Translation("Paragraphs"),
+ *   label_singular = @Translation("Paragraph"),
+ *   label_plural = @Translation("Paragraphs"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count Paragraph",
+ *     plural = "@count Paragraphs",
+ *   ),
  *   bundle_label = @Translation("Paragraph type"),
  *   handlers = {
  *     "view_builder" = "Drupal\paragraphs\ParagraphViewBuilder",
@@ -58,9 +65,6 @@
  *     "revision" = "revision_id",
  *     "published" = "status"
  *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_uid",
- *   },
  *   bundle_entity_type = "paragraphs_type",
  *   field_ui_base_route = "entity.paragraphs_type.edit_form",
  *   common_reference_revisions_target = TRUE,
@@ -143,18 +147,25 @@ public function setParentEntity(ContentEntityInterface $parent, $parent_field_na
    * {@inheritdoc}
    */
   public function label() {
-    $label = '';
-    if ($parent = $this->getParentEntity()) {
+    if (($parent = $this->getParentEntity()) && $parent->hasField($this->get('parent_field_name')->value)) {
       $parent_field = $this->get('parent_field_name')->value;
-      $values = $parent->{$parent_field};
-      foreach ($values as $key => $value) {
+      $field = $parent->get($parent_field);
+      $found = FALSE;
+      foreach ($field as $key => $value) {
         if ($value->entity->id() == $this->id()) {
-          $label = $parent->label() . ' > ' . $value->getFieldDefinition()->getLabel();
-        } else {
-          // A previous or draft revision or a deleted stale Paragraph.
-          $label = $parent->label() . ' > ' . $value->getFieldDefinition()->getLabel() . ' (previous revision)';
+          $found = TRUE;
+          break;
         }
       }
+      if ($found) {
+        $label = $parent->label() . ' > ' . $field->getFieldDefinition()->getLabel();
+      } else {
+        // A previous or draft revision or a deleted stale Paragraph.
+        $label = $parent->label() . ' > ' . $field->getFieldDefinition()->getLabel() . ' (previous revision)';
+      }
+    }
+    else {
+      $label = t('Orphaned @type: @summary', ['@summary' => Unicode::truncate(strip_tags($this->getSummary()), 50, FALSE, TRUE), '@type' => $this->get('type')->entity->label()]);
     }
     return $label;
   }
@@ -165,16 +176,6 @@ public function label() {
   public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
-    // If no owner has been set explicitly, make the current user the owner.
-    if (!$this->getOwner()) {
-      $this->setOwnerId(\Drupal::currentUser()->id());
-    }
-    // If no revision author has been set explicitly, make the node owner the
-    // revision author.
-    if (!$this->getRevisionAuthor()) {
-      $this->setRevisionAuthorId($this->getOwnerId());
-    }
-
     // If behavior settings are not set then get them from the entity.
     if ($this->unserializedBehaviorSettings !== NULL) {
       $this->set('behavior_settings', serialize($this->unserializedBehaviorSettings));
@@ -247,31 +248,53 @@ public function getCreatedTime() {
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function getOwner() {
-    return $this->get('uid')->entity;
+    $parent = $this->getParentEntity();
+    if ($parent instanceof EntityOwnerInterface) {
+      return $parent->getOwner();
+    }
+    else {
+      return NULL;
+    }
   }
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function getOwnerId() {
-    return $this->get('uid')->target_id;
+    $parent = $this->getParentEntity();
+    if ($parent instanceof EntityOwnerInterface) {
+      return $parent->getOwnerId();
+    }
+    else {
+      return NULL;
+    }
   }
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function setOwnerId($uid) {
-    $this->set('uid', $uid);
     return $this;
   }
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function setOwner(UserInterface $account) {
-    $this->set('uid', $account->id());
     return $this;
   }
 
@@ -291,16 +314,27 @@ public function getParagraphType() {
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function getRevisionAuthor() {
-    return $this->get('revision_uid')->entity;
+    $parent = $this->getParentEntity();
+
+    if ($parent) {
+      return $parent->get('revision_uid')->entity;
+    }
+
+    return NULL;
   }
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated Paragraphs no longer have their own author,
+   *  check the parent entity instead.
    */
   public function setRevisionAuthorId($uid) {
-    $this->set('revision_uid', $uid);
     return $this;
   }
 
@@ -329,20 +363,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setDescription(t('The paragraphs entity language code.'))
       ->setRevisionable(TRUE);
 
-    $fields['uid'] = BaseFieldDefinition::create('entity_reference')
-      ->setLabel(t('Authored by'))
-      ->setDescription(t('The user ID of the paragraphs author.'))
-      ->setRevisionable(TRUE)
-      ->setSetting('target_type', 'user')
-      ->setSetting('handler', 'default')
-      ->setDefaultValueCallback('Drupal\paragraphs\Entity\Paragraph::getCurrentUserId')
-      ->setTranslatable(TRUE)
-      ->setDisplayOptions('form', array(
-        'region' => 'hidden',
-        'weight' => 0,
-      ))
-      ->setDisplayConfigurable('form', TRUE);
-
     $fields['status'] = BaseFieldDefinition::create('boolean')
       ->setLabel(t('Published'))
       ->setRevisionable(TRUE)
@@ -361,28 +381,25 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ))
       ->setDisplayConfigurable('form', TRUE);
 
-    $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference')
-      ->setLabel(t('Revision user ID'))
-      ->setDescription(t('The user ID of the author of the current revision.'))
-      ->setSetting('target_type', 'user')
-      ->setRevisionable(TRUE);
-
     $fields['parent_id'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Parent ID'))
       ->setDescription(t('The ID of the parent entity of which this entity is referenced.'))
-      ->setSetting('is_ascii', TRUE);
+      ->setSetting('is_ascii', TRUE)
+      ->setRevisionable(TRUE);
 
     $fields['parent_type'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Parent type'))
       ->setDescription(t('The entity parent type to which this entity is referenced.'))
       ->setSetting('is_ascii', TRUE)
-      ->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH);
+      ->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH)
+      ->setRevisionable(TRUE);
 
     $fields['parent_field_name'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Parent field name'))
       ->setDescription(t('The entity parent field name to which this entity is referenced.'))
       ->setSetting('is_ascii', TRUE)
-      ->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH);
+      ->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH)
+      ->setRevisionable(TRUE);
 
     $fields['behavior_settings'] = BaseFieldDefinition::create('string_long')
       ->setLabel(t('Behavior settings'))
@@ -393,29 +410,17 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     return $fields;
   }
 
-  /**
-   * Default value callback for 'uid' base field definition.
-   *
-   * @see ::baseFieldDefinitions()
-   *
-   * @return array
-   *   An array of default values.
-   */
-  public static function getCurrentUserId() {
-    return array(\Drupal::currentUser()->id());
-  }
-
   /**
   * {@inheritdoc}
   */
  public function createDuplicate() {
    $duplicate = parent::createDuplicate();
    // Loop over entity fields and duplicate nested paragraphs.
-   foreach ($duplicate->getFields() as $field) {
-     if ($field->getFieldDefinition()->getType() == 'entity_reference_revisions') {
-       if ($field->getFieldDefinition()->getTargetEntityTypeId() == "paragraph") {
-         foreach ($field as $item) {
-           $item->entity = $item->entity->createDuplicate();
+   foreach ($duplicate->getFields() as $fieldItemList) {
+     if ($fieldItemList instanceof EntityReferenceFieldItemListInterface && $fieldItemList->getSetting('target_type') === $this->getEntityTypeId()) {
+       foreach ($fieldItemList as $delta => $item) {
+         if ($item->entity) {
+           $fieldItemList[$delta] = $item->entity->createDuplicate();
          }
        }
      }
@@ -427,10 +432,26 @@ public function createDuplicate() {
    * {@inheritdoc}
    */
   public function getSummary(array $options = []) {
+    $summary_items = $this->getSummaryItems($options);
+    $summary = [
+      '#theme' => 'paragraphs_summary',
+      '#summary' => $summary_items,
+      '#expanded' => isset($options['expanded']) ? $options['expanded'] : FALSE,
+    ];
+
+    return \Drupal::service('renderer')->renderPlain($summary);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummaryItems(array $options = []) {
+    $summary = ['content' => [], 'behaviors' => []];
     $show_behavior_summary = isset($options['show_behavior_summary']) ? $options['show_behavior_summary'] : TRUE;
     $depth_limit = isset($options['depth_limit']) ? $options['depth_limit'] : 1;
+
+    // Add content summary items.
     $this->summaryCount = 0;
-    $summary = [];
     $components = entity_get_form_display('paragraph', $this->getType(), 'default')->getComponents();
     uasort($components, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
     foreach (array_keys($components) as $field_name) {
@@ -448,40 +469,43 @@ public function getSummary(array $options = []) {
       if ($field_definition->getType() == 'image' || $field_definition->getType() == 'file') {
         $file_summary = $this->getFileSummary($field_name);
         if ($file_summary != '') {
-          $summary[] = $file_summary;
+          $summary['content'][] = $file_summary;
         }
       }
 
       $text_summary = $this->getTextSummary($field_name, $field_definition);
       if ($text_summary != '') {
-        $summary[] = $text_summary;
+        $summary['content'][] = $text_summary;
       }
 
       if ($field_definition->getType() == 'entity_reference_revisions') {
         // Decrease the depth, since we are entering a nested paragraph.
         $nested_summary = $this->getNestedSummary($field_name, [
-          'show_behavior_summary' => $show_behavior_summary,
+          'show_behavior_summary' => FALSE,
           'depth_limit' => $depth_limit - 1
         ]);
-        if ($nested_summary != '') {
-          $summary[] = $nested_summary;
-        }
+        $summary['content'] = array_merge($summary['content'], $nested_summary);
       }
 
-      if ($field_type = $field_definition->getType() == 'entity_reference') {
-        if ($this->get($field_name)->entity && $this->get($field_name)->entity->access('view label')) {
-          $entity = $this->get($field_name)->entity;
-          // Switch to the entity translation in the current context if exists.
-          $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode);
-          $summary[] = $entity->label();
+      if ($field_definition->getType() === 'entity_reference') {
+        $referenced_entities = $this->get($field_name)->referencedEntities();
+        /** @var \Drupal\Core\Entity\EntityInterface[] $referenced_entities */
+        foreach ($referenced_entities as $referenced_entity) {
+          if ($referenced_entity->access('view label')) {
+            // Switch to the entity translation in the current context.
+            $entity = \Drupal::service('entity.repository')->getTranslationFromContext($referenced_entity, $this->activeLangcode);
+            $summary['content'][] = $entity->label();
+          }
         }
       }
 
       // Add the Block admin label referenced by block_field.
       if ($field_definition->getType() == 'block_field') {
         if (!empty($this->get($field_name)->first())) {
-          $block_admin_label = $this->get($field_name)->first()->getBlock()->getPluginDefinition()['admin_label'];
-          $summary[] = $block_admin_label;
+          if ($block = $block_admin_label = $this->get($field_name)->first()->getBlock()) {
+            $block_admin_label = $block->getPluginDefinition()['admin_label'];
+          }
+          $summary['content'][] = $block_admin_label;
         }
       }
 
@@ -489,26 +513,31 @@ public function getSummary(array $options = []) {
         if (!empty($this->get($field_name)->first())) {
           // If title is not set, fallback to the uri.
           if ($title = $this->get($field_name)->title) {
-            $summary[] = $title;
+            $summary['content'][] = $title;
           }
           else {
-            $summary[] = $this->get($field_name)->uri;
+            $summary['content'][] = $this->get($field_name)->uri;
           }
         }
       }
     }
 
+    // Add behaviors summary items.
     if ($show_behavior_summary) {
       $paragraphs_type = $this->getParagraphType();
       foreach ($paragraphs_type->getEnabledBehaviorPlugins() as $plugin_id => $plugin) {
         if ($plugin_summary = $plugin->settingsSummary($this)) {
-          $summary = array_merge($summary, $plugin_summary);
+          foreach ($plugin_summary as $plugin_summary_element) {
+            if (!is_array($plugin_summary_element)) {
+              $plugin_summary_element = ['value' => $plugin_summary_element];
+            }
+            $summary['behaviors'][] = $plugin_summary_element;
+          }
         }
       }
     }
 
-    $collapsed_summary_text = implode(', ', $summary);
-    return strip_tags($collapsed_summary_text);
+    return $summary;
   }
 
   /**
@@ -551,8 +580,7 @@ public function getIcons(array $options = []) {
   protected function getFieldsToSkipFromChangedCheck() {
     // A list of revision fields which should be skipped from the comparision.
     $fields = [
-      $this->getEntityType()->getKey('revision'),
-      'revision_uid'
+      $this->getEntityType()->getKey('revision')
     ];
 
     return $fields;
@@ -631,7 +659,7 @@ protected function getFileSummary($field_name) {
         elseif ($file_value->alt != '') {
           $text = $file_value->alt;
         }
-        elseif ($file_value->entity->getFileName()) {
+        elseif ($file_value->entity && $file_value->entity->getFileName()) {
           $text = $file_value->entity->getFileName();
         }
 
@@ -647,7 +675,7 @@ protected function getFileSummary($field_name) {
   }
 
   /**
-   * Returns summary for nested paragraphs.
+   * Returns summary items for nested paragraphs.
    *
    * @param string $field_name
    *   Field definition id for paragraph.
@@ -656,32 +684,25 @@ protected function getFileSummary($field_name) {
    *   See \Drupal\paragraphs\ParagraphInterface::getSummary() for all of the
    *   available options.
    *
-   * @return string
-   *   Short summary for nested Paragraphs type
-   *   or NULL if the summary is empty.
+   * @return array
+   *   List of content summary items for nested elements.
    */
   protected function getNestedSummary($field_name, array $options) {
-    $summary = [];
+    $summary_content = [];
     if ($options['depth_limit'] >= 0) {
       foreach ($this->get($field_name) as $item) {
         $entity = $item->entity;
         if ($entity instanceof ParagraphInterface) {
           // Switch to the entity translation in the current context if exists.
           $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $this->activeLangcode);
-          $summary[] = $entity->getSummary($options);
+          $content_summary_items = $entity->getSummaryItems($options)['content'];
+          $summary_content = array_merge($summary_content, array_values($content_summary_items));
           $this->summaryCount++;
         }
       }
     }
 
-    $summary = array_filter($summary);
-
-    if (empty($summary)) {
-      return NULL;
-    }
-
-    $paragraph_summary = implode(', ', $summary);
-    return $paragraph_summary;
+    return $summary_content;
   }
 
   /**
@@ -717,14 +738,11 @@ public function getTextSummary($field_name, FieldDefinitionInterface $field_defi
       }
 
       $text = $this->get($field_name)->value;
-      if (strlen($text) > 150) {
-        $text = Unicode::truncate($text, 150);
-      }
-
-      $summary = trim(strip_tags($text));
+      $summary = Unicode::truncate(trim(strip_tags($text)), 150);
       if (empty($summary)) {
-        // Tease raw HTML to have at least some summary.
-        $summary = htmlspecialchars(trim($text));
+        // Autoescape is applied to the summary when it is rendered with twig,
+        // make it a Markup object so HTML tags are displayed correctly.
+        $summary = Markup::create(Unicode::truncate(htmlspecialchars(trim($text)), 150));
       }
     }
 
diff --git a/web/modules/paragraphs/src/Entity/ParagraphsType.php b/web/modules/paragraphs/src/Entity/ParagraphsType.php
index fb06b01747..9b815c0988 100644
--- a/web/modules/paragraphs/src/Entity/ParagraphsType.php
+++ b/web/modules/paragraphs/src/Entity/ParagraphsType.php
@@ -5,16 +5,26 @@
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
+use Drupal\file\Entity\File;
 use Drupal\paragraphs\ParagraphsBehaviorCollection;
 use Drupal\paragraphs\ParagraphsTypeInterface;
+use Drupal\Core\File\FileSystemInterface;
 
-/**
+  /**
  * Defines the ParagraphsType entity.
  *
  * @ConfigEntityType(
  *   id = "paragraphs_type",
  *   label = @Translation("Paragraphs type"),
+ *   label_collection = @Translation("Paragraphs types"),
+ *   label_singular = @Translation("Paragraphs type"),
+ *   label_plural = @Translation("Paragraphs types"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count Paragraphs type",
+ *     plural = "@count Paragraphs types",
+ *   ),
  *   handlers = {
+ *     "access" = "Drupal\paragraphs\ParagraphsTypeAccessControlHandler",
  *     "list_builder" = "Drupal\paragraphs\Controller\ParagraphsTypeListBuilder",
  *     "form" = {
  *       "add" = "Drupal\paragraphs\Form\ParagraphsTypeForm",
@@ -32,6 +42,7 @@
  *     "id",
  *     "label",
  *     "icon_uuid",
+ *     "icon_default",
  *     "description",
  *     "behavior_plugins",
  *   },
@@ -73,6 +84,13 @@ class ParagraphsType extends ConfigEntityBundleBase implements ParagraphsTypeInt
    */
   protected $icon_uuid;
 
+  /**
+   * Default icon encoded as data URL scheme (RFC 2397).
+   *
+   * @var string
+   */
+  protected $icon_default;
+
   /**
    * The Paragraphs type behavior plugins configuration keyed by their id.
    *
@@ -88,11 +106,61 @@ class ParagraphsType extends ConfigEntityBundleBase implements ParagraphsTypeInt
    */
   protected $behaviorCollection;
 
+  /**
+   * Restores the icon file from the default icon value.
+   *
+   * @return \Drupal\file\FileInterface|bool
+   *   The icon's file entity or FALSE if no default icon set.
+   */
+  protected function restoreDefaultIcon() {
+    // Default icon data in RFC 2397 format ("data" URL scheme).
+    if ($this->icon_default && $icon_data = fopen($this->icon_default, 'r')) {
+      // Compose the default icon file destination.
+      $icon_meta = stream_get_meta_data($icon_data);
+      // File extension from MIME, only JPG/JPEG, PNG and SVG expected.
+      list(, $icon_file_ext) = explode('image/', $icon_meta['mediatype']);
+      // SVG special case.
+      if ($icon_file_ext == 'svg+xml') {
+        $icon_file_ext = 'svg';
+      }
+
+      $filesystem = \Drupal::service('file_system');
+      $icon_upload_path = ParagraphsTypeInterface::ICON_UPLOAD_LOCATION;
+      $icon_file_destination = $icon_upload_path . $this->id() . '-default-icon.' . $icon_file_ext;
+      // Check the directory exists before writing data to it.
+      $filesystem->prepareDirectory($icon_upload_path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
+      // Save the default icon file.
+      $icon_file_uri = $filesystem->saveData($icon_data, $icon_file_destination);
+      if ($icon_file_uri) {
+        // Create the icon file entity.
+        $icon_entity_values = [
+          'uri' => $icon_file_uri,
+          'uid' => \Drupal::currentUser()->id(),
+          'uuid' => $this->icon_uuid,
+          'status' => FILE_STATUS_PERMANENT,
+        ];
+
+        // Delete existent icon file if it exists.
+        if ($old_icon = $this->getFileByUuid($this->icon_uuid)) {
+          $old_icon->delete();
+        }
+
+        $new_icon = File::create($icon_entity_values);
+        $new_icon->save();
+        $this->updateFileIconUsage($new_icon, $old_icon);
+        return $new_icon;
+      }
+    }
+
+    return FALSE;
+  }
+
   /**
    * {@inheritdoc}
    */
   public function getIconFile() {
-    if ($this->icon_uuid && $icon = $this->getFileByUuid($this->icon_uuid)) {
+    $icon = $this->getFileByUuid($this->icon_uuid) ?: $this->restoreDefaultIcon();
+    if ($this->icon_uuid && $icon) {
       return $icon;
     }
 
@@ -141,6 +209,29 @@ public function calculateDependencies() {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function onDependencyRemoval(array $dependencies) {
+    $changed = parent::onDependencyRemoval($dependencies);
+    $behavior_plugins = $this->getBehaviorPlugins();
+    foreach ($dependencies['module'] as $module) {
+      /** @var \Drupal\Component\Plugin\PluginInspectionInterface $plugin */
+      foreach ($behavior_plugins as $instance_id => $plugin) {
+        $definition = (array) $plugin->getPluginDefinition();
+        // If a module providing a behavior plugin is being uninstalled,
+        // remove the plugin and dependency so this paragraph bundle is not
+        // deleted too.
+        if (isset($definition['provider']) && $definition['provider'] === $module) {
+          unset($this->behavior_plugins[$instance_id]);
+          $this->getBehaviorPlugins()->removeInstanceId($instance_id);
+          $changed = TRUE;
+        }
+      }
+    }
+    return $changed;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -180,24 +271,12 @@ public function hasEnabledBehaviorPlugin($plugin_id) {
    * {@inheritdoc}
    */
   public function postSave(EntityStorageInterface $storage, $update = TRUE) {
-    // Update the file usage for the icon files.
     if (!$update || $this->icon_uuid != $this->original->icon_uuid) {
-      // The icon has changed. Update file usage.
-      /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
-      $file_usage = \Drupal::service('file.usage');
-
-      // Add usage of the new icon file, if it exists. It might not exist, if
-      // this Paragraphs type was imported as configuration, or if the icon has
-      // just been removed.
-      if ($this->icon_uuid && $new_icon = $this->getFileByUuid($this->icon_uuid)) {
-        $file_usage->add($new_icon, 'paragraphs', 'paragraphs_type', $this->id());
-      }
-      if ($update) {
-        // Delete usage of the old icon file, if it exists.
-        if ($this->original->icon_uuid && $old_icon = $this->getFileByUuid($this->original->icon_uuid)) {
-          $file_usage->delete($old_icon, 'paragraphs', 'paragraphs_type', $this->id());
-        }
-      }
+      // Update the file usage for the icon file.
+      $new_icon_file = $this->icon_uuid ? $this->getFileByUuid($this->icon_uuid) : FALSE;
+      // Update the file usage of the old icon as well if the icon was changed.
+      $old_icon_file = $update && $this->original->icon_uuid ? $this->getFileByUuid($this->original->icon_uuid) : FALSE;
+      $this->updateFileIconUsage($new_icon_file, $old_icon_file);
     }
 
     parent::postSave($storage, $update);
@@ -210,17 +289,36 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    *   The file entity's UUID.
    *
    * @return \Drupal\file\FileInterface|null
-   *  The file entity. NULL if the UUID is invalid.
+   *   The file entity. NULL if the UUID is invalid.
    */
   protected function getFileByUuid($uuid) {
-    $files = $this->entityTypeManager()
-      ->getStorage('file')
-      ->loadByProperties(['uuid' => $uuid]);
-    if ($files) {
-      return current($files);
+    if ($id = \Drupal::service('paragraphs_type.uuid_lookup')->get($uuid)) {
+      return $this->entityTypeManager()->getStorage('file')->load($id);
     }
 
     return NULL;
   }
 
+  /**
+   * Updates the icon file usage information.
+   *
+   * @param \Drupal\file\FileInterface|mixed $new_icon
+   *   The new icon file, FALSE on deletion.
+   * @param \Drupal\file\FileInterface|mixed $old_icon
+   *   (optional) Old icon, on update or deletion.
+   */
+  protected function updateFileIconUsage($new_icon, $old_icon = FALSE) {
+    /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
+    $file_usage = \Drupal::service('file.usage');
+
+    if ($new_icon) {
+      // Add usage of the new icon file.
+      $file_usage->add($new_icon, 'paragraphs', 'paragraphs_type', $this->id());
+    }
+    if ($old_icon) {
+      // Delete usage of the old icon file.
+      $file_usage->delete($old_icon, 'paragraphs', 'paragraphs_type', $this->id());
+    }
+  }
+
 }
diff --git a/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php b/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php
index b71cd84ead..e025ad8628 100644
--- a/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php
+++ b/web/modules/paragraphs/src/Feeds/Target/Paragraphs.php
@@ -15,7 +15,7 @@
  * @FeedsTarget(
  *   id = "paragraphs",
  *   field_types = {"entity_reference_revisions"},
- *   arguments = {"@entity.manager", "@current_user"}
+ *   arguments = {"@entity_type.manager", "@current_user"}
  * )
  */
 class Paragraphs extends Text implements ConfigurableTargetInterface {
diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
index 6642d18079..ac6bb77c35 100644
--- a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
+++ b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
@@ -56,7 +56,7 @@ public function deleteExistingEntities(array $form, FormStateInterface $form_sta
 
       // Delete existing entities.
       $storage->delete($paragraphs);
-      drupal_set_message($this->formatPlural(count($paragraphs), 'Entity is successfully deleted.', 'All @count entities are successfully deleted.'));
+      $this->messenger()->addMessage($this->formatPlural(count($paragraphs), 'Entity is successfully deleted.', 'All @count entities are successfully deleted.'));
     }
 
     // Set form to rebuild.
diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
index cf20195b3f..c92774da52 100644
--- a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
+++ b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
@@ -5,10 +5,11 @@
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\SubformState;
-use Drupal\Core\Messenger\Messenger;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\field_ui\FieldUI;
 use Drupal\paragraphs\ParagraphsBehaviorManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\paragraphs\ParagraphsTypeInterface;
 
 /**
  * Form controller for paragraph type forms.
@@ -41,10 +42,10 @@ class ParagraphsTypeForm extends EntityForm {
    *
    * @param \Drupal\paragraphs\ParagraphsBehaviorManager $paragraphs_behavior_manager
    *   The paragraphs type feature manager service.
-   * @param \Drupal\Core\Messenger\Messenger $messenger
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger service.
    */
-  public function __construct(ParagraphsBehaviorManager $paragraphs_behavior_manager, Messenger $messenger) {
+  public function __construct(ParagraphsBehaviorManager $paragraphs_behavior_manager, MessengerInterface $messenger) {
     $this->paragraphsBehaviorManager = $paragraphs_behavior_manager;
     $this->messenger = $messenger;
   }
@@ -95,7 +96,7 @@ public function form(array $form, FormStateInterface $form_state) {
     $form['icon_file'] = [
       '#title' => $this->t('Paragraph type icon'),
       '#type' => 'managed_file',
-      '#upload_location' => 'public://paragraphs_type_icon/',
+      '#upload_location' => ParagraphsTypeInterface::ICON_UPLOAD_LOCATION,
       '#upload_validators' => [
         'file_validate_extensions' => ['png jpg svg'],
       ],
@@ -116,12 +117,12 @@ public function form(array $form, FormStateInterface $form_state) {
     if ($behavior_plugin_definitions = $this->paragraphsBehaviorManager->getApplicableDefinitions($paragraphs_type)) {
       $form['message'] = [
         '#type' => 'container',
-        '#markup' => $this->t('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget.'),
+        '#markup' => $this->t('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget.', [], ['context' => 'paragraphs']),
         '#attributes' => ['class' => ['messages', 'messages--warning']]
       ];
       $form['behavior_plugins'] = [
         '#type' => 'details',
-        '#title' => $this->t('Behaviors'),
+        '#title' => $this->t('Behaviors', [], ['context' => 'paragraphs']),
         '#tree' => TRUE,
         '#open' => TRUE
       ];
@@ -168,12 +169,16 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
     $paragraphs_type = $this->entity;
 
     $icon_file = $form_state->getValue(['icon_file', '0']);
-    // Set the file UUID to the paragraph configuration.
+    // Set the icon file UUID and default value to the paragraph configuration.
     if (!empty($icon_file) && $file = $this->entityTypeManager->getStorage('file')->load($icon_file)) {
       $paragraphs_type->set('icon_uuid', $file->uuid());
+      $paragraphs_type->set(
+        'icon_default',
+        'data:' . $file->getMimeType() . ';base64,' . base64_encode(file_get_contents($file->getFileUri())));
     }
     else {
       $paragraphs_type->set('icon_uuid', NULL);
+      $paragraphs_type->set('icon_default', NULL);
     }
 
     if ($behavior_plugin_definitions = $this->paragraphsBehaviorManager->getApplicableDefinitions($paragraphs_type)) {
@@ -218,7 +223,7 @@ public function save(array $form, FormStateInterface $form_state) {
     $this->messenger->addMessage($this->t('Saved the %label Paragraphs type.', array(
       '%label' => $paragraphs_type->label(),
     )));
-    if (($status == SAVED_NEW && \Drupal::moduleHandler()->moduleExists('field_ui'))
+    if (($status == SAVED_NEW && $this->moduleHandler->moduleExists('field_ui'))
       && $route_info = FieldUI::getOverviewRouteInfo('paragraph', $paragraphs_type->id())) {
       $form_state->setRedirectUrl($route_info);
     }
@@ -234,7 +239,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
     $form = parent::actions($form, $form_state);
 
     // We want to display the button only on add page.
-    if ($this->entity->isNew() && \Drupal::moduleHandler()->moduleExists('field_ui')) {
+    if ($this->entity->isNew() && $this->moduleHandler->moduleExists('field_ui')) {
       $form['submit']['#value'] = $this->t('Save and manage fields');
     }
 
diff --git a/web/modules/paragraphs/src/ParagraphInterface.php b/web/modules/paragraphs/src/ParagraphInterface.php
index b3a3181114..6d7969b345 100644
--- a/web/modules/paragraphs/src/ParagraphInterface.php
+++ b/web/modules/paragraphs/src/ParagraphInterface.php
@@ -36,7 +36,7 @@ public function getParentEntity();
   public function setParentEntity(ContentEntityInterface $parent, $parent_field_name);
 
   /**
-   * Returns short summary for paragraph.
+   * Returns a short summary for the Paragraph.
    *
    * @param array $options
    *   (optional) Array of additional options, with the following elements:
@@ -47,10 +47,26 @@ public function setParentEntity(ContentEntityInterface $parent, $parent_field_na
    *     allowed. Defaults to 1 to show nested paragraphs only on top level.
    *
    * @return string
-   *   The text without tags.
+   *   The template based summary.
    */
   public function getSummary(array $options = []);
 
+  /**
+   * Returns the summary items of the Paragraph.
+   *
+   * @param array $options
+   *   (optional) Array of additional options, with the following elements:
+   *   - 'show_behavior_summary': Whether the summary should contain the
+   *     behavior settings. Defaults to TRUE to show behavior settings in the
+   *     summary.
+   *   - 'depth_limit': Depth limit of how many nested paragraph summaries are
+   *     allowed. Defaults to 1 to show nested paragraphs only on top level.
+   *
+   * @return array
+   *   A list of summary items, grouped into the keys 'content' and 'behaviors'.
+   */
+  public function getSummaryItems(array $options = []);
+
   /**
    * Returns info icons render array for a paragraph.
    *
diff --git a/web/modules/paragraphs/src/ParagraphStorageSchema.php b/web/modules/paragraphs/src/ParagraphStorageSchema.php
index d79c4ce038..e37a769888 100644
--- a/web/modules/paragraphs/src/ParagraphStorageSchema.php
+++ b/web/modules/paragraphs/src/ParagraphStorageSchema.php
@@ -17,7 +17,10 @@ class ParagraphStorageSchema extends SqlContentEntityStorageSchema {
   protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
     $schema = parent::getEntitySchema($entity_type, $reset);
 
-    $schema['paragraphs_item_field_data']['indexes'] += array(
+    $schema[$this->storage->getDataTable()]['indexes'] += array(
+      'paragraphs__parent_fields' => array('parent_type', 'parent_id', 'parent_field_name'),
+    );
+    $schema[$this->storage->getRevisionDataTable()]['indexes'] += array(
       'paragraphs__parent_fields' => array('parent_type', 'parent_id', 'parent_field_name'),
     );
 
diff --git a/web/modules/paragraphs/src/ParagraphsBehaviorBase.php b/web/modules/paragraphs/src/ParagraphsBehaviorBase.php
index f2cf8915a5..6edd3c1daa 100644
--- a/web/modules/paragraphs/src/ParagraphsBehaviorBase.php
+++ b/web/modules/paragraphs/src/ParagraphsBehaviorBase.php
@@ -2,9 +2,9 @@
 
 namespace Drupal\paragraphs;
 
-use Drupal\Core\Plugin\PluginBase;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityFieldManager;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\field\FieldConfigInterface;
@@ -30,10 +30,10 @@ abstract class ParagraphsBehaviorBase extends PluginBase implements ParagraphsBe
    *   The plugin_id for the plugin instance.
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
-   * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager
+   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
    *   The entity field manager.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityFieldManager $entity_field_manager) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityFieldManagerInterface $entity_field_manager) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->configuration += $this->defaultConfiguration();
     $this->entityFieldManager = $entity_field_manager;
diff --git a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
index b152d5ec3e..e3ecb3b87a 100644
--- a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
+++ b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
@@ -2,10 +2,11 @@
 
 namespace Drupal\paragraphs;
 
+use Drupal\Component\Plugin\ConfigurableInterface;
+use Drupal\Component\Plugin\DependentPluginInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -16,7 +17,7 @@
  * adding properties and attributes, it can also add extra classes to the render
  * elements so extra styling can be applied.
  */
-interface ParagraphsBehaviorInterface extends PluginFormInterface, ConfigurablePluginInterface {
+interface ParagraphsBehaviorInterface extends PluginFormInterface, ConfigurableInterface, DependentPluginInterface {
 
   /**
    * Builds a behavior perspective for each paragraph based on its type.
diff --git a/web/modules/paragraphs/src/ParagraphsServiceProvider.php b/web/modules/paragraphs/src/ParagraphsServiceProvider.php
index d781b8e183..db38ed640e 100644
--- a/web/modules/paragraphs/src/ParagraphsServiceProvider.php
+++ b/web/modules/paragraphs/src/ParagraphsServiceProvider.php
@@ -15,7 +15,7 @@ class ParagraphsServiceProvider extends ServiceProviderBase {
   /**
    * {@inheritdoc}
    */
-  public function alter(ContainerBuilder $container) {
+  public function register(ContainerBuilder $container) {
     $modules = $container->getParameter('container.modules');
     // Check for installed Replicate module.
     if (isset($modules['replicate']) ) {
diff --git a/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php b/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php
new file mode 100644
index 0000000000..0bf68e342a
--- /dev/null
+++ b/web/modules/paragraphs/src/ParagraphsTypeAccessControlHandler.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\paragraphs;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Defines the access control handler for the Paragraphs type entity type.
+ *
+ * @see \Drupal\paragraphs\Entity\ParagraphsType
+ */
+class ParagraphsTypeAccessControlHandler extends EntityAccessControlHandler {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $viewLabelOperation = TRUE;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+    switch ($operation) {
+      case 'view label':
+        return AccessResult::allowedIfHasPermission($account, 'access content');
+      default:
+        return parent::checkAccess($entity, $operation, $account);
+    }
+  }
+
+}
diff --git a/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
new file mode 100644
index 0000000000..9786eb1023
--- /dev/null
+++ b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\paragraphs;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\CacheCollector;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Lock\LockBackendInterface;
+
+/**
+ * A cache collector that caches IDs for the paragraphs_type entity icon UUIDs.
+ */
+class ParagraphsTypeIconUuidLookup extends CacheCollector {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs a ParagraphsTypeIconUuidLookup instance.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   The cache backend.
+   * @param \Drupal\Core\Lock\LockBackendInterface $lock
+   *   The lock backend.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct('paragraphs_type_icon_uuid', $cache, $lock);
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function resolveCacheMiss($key) {
+    $ids = $this->entityTypeManager->getStorage('file')->getQuery()
+      ->condition('uuid', $key)
+      ->execute();
+
+    // Only cache if there is a match, otherwise creating new entities would
+    // require to invalidate the cache.
+    $id = reset($ids);
+    if ($id) {
+      $this->storage[$key] = $id;
+      $this->persist($key);
+    }
+    return $id;
+  }
+
+}
diff --git a/web/modules/paragraphs/src/ParagraphsTypeInterface.php b/web/modules/paragraphs/src/ParagraphsTypeInterface.php
index 9eb889ea30..9cee2ee496 100644
--- a/web/modules/paragraphs/src/ParagraphsTypeInterface.php
+++ b/web/modules/paragraphs/src/ParagraphsTypeInterface.php
@@ -9,6 +9,13 @@
  */
 interface ParagraphsTypeInterface extends ConfigEntityInterface {
 
+  /**
+   * Icon upload location.
+   *
+   * @var string
+   */
+  const ICON_UPLOAD_LOCATION = 'public://paragraphs_type_icon/';
+
   /**
    * Returns the ordered collection of feature plugin instances.
    *
diff --git a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
index 3d8e4e27d7..2aa7acd0cc 100644
--- a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
+++ b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
@@ -2,15 +2,10 @@
 
 namespace Drupal\paragraphs\Plugin\EntityReferenceSelection;
 
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Component\Utility\NestedArray;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Default plugin implementation of the Entity Reference Selection plugin.
@@ -25,52 +20,6 @@
  */
 class ParagraphSelection extends DefaultSelection {
 
-  /**
-   * Entity type bundle info service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
-   */
-  public $entityTypeBundleInfo;
-
-  /**
-   * ParagraphSelection constructor.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin_id for the plugin instance.
-   * @param mixed $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager service.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler service.
-   * @param \Drupal\Core\Session\AccountInterface $current_user
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   Entity type bundle info service.
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $module_handler, $current_user);
-
-    $this->entityTypeBundleInfo = $entity_type_bundle_info;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static(
-      $configuration,
-      $plugin_id,
-      $plugin_definition,
-      $container->get('entity.manager'),
-      $container->get('module_handler'),
-      $container->get('current_user'),
-      $container->get('entity_type.bundle.info')
-    );
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -176,7 +125,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       $weight++;
     }
 
-    if (!count($bundle_options)) {
+    if (empty($bundle_options)) {
       $form['allowed_bundles_explain'] = [
         '#type' => 'markup',
         '#markup' => $this->t('You did not add any Paragraph types yet, click <a href=":here">here</a> to add one.', [':here' => Url::fromRoute('paragraphs.type_add')->toString()]),
@@ -297,9 +246,9 @@ public function validateReferenceableNewEntities(array $entities) {
   protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
     $target_type = $this->configuration['target_type'];
     $handler_settings = $this->configuration['handler_settings'];
-    $entity_type = $this->entityManager->getDefinition($target_type);
+    $entity_type = $this->entityTypeManager->getDefinition($target_type);
 
-    $query = $this->entityManager->getStorage($target_type)->getQuery();
+    $query = $this->entityTypeManager->getStorage($target_type)->getQuery();
 
     // If 'target_bundles' is NULL, all bundles are referenceable, no further
     // conditions are needed.
diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php b/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php
index 2e0bc36332..6987d5ba54 100644
--- a/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php
+++ b/web/modules/paragraphs/src/Plugin/Field/FieldFormatter/ParagraphsSummaryFormatter.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase;
-use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\paragraphs\ParagraphInterface;
 
 /**
@@ -28,7 +27,6 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
     $elements = [];
     foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) {
       if ($entity->id()) {
-        $summary = $entity->getSummary();
         $elements[$delta] = [
           '#type' => 'container',
           '#attributes' => [
@@ -49,9 +47,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
           ]
         ];
         $elements[$delta]['summary']['description'] = [
-          '#markup' => $summary,
-          '#prefix' => '<div class="paragraphs-collapsed-description">',
-          '#suffix' => '</div>',
+          '#theme' => 'paragraphs_summary',
+          '#summary' => $entity->getSummaryItems(),
         ];
       }
     }
diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
index 48d6d2c48e..4fe506f939 100644
--- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
+++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -6,8 +6,6 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
-use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldFilteredMarkup;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -15,13 +13,10 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Render\Element;
-use Drupal\node\Entity\Node;
-use Drupal\paragraphs;
 use Drupal\paragraphs\ParagraphInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 use Drupal\paragraphs\Plugin\EntityReferenceSelection\ParagraphSelection;
 
-
 /**
  * Plugin implementation of the 'entity_reference paragraphs' widget.
  *
@@ -235,7 +230,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     $host = $items->getEntity();
     $widget_state = static::getWidgetState($parents, $field_name, $form_state);
 
-    $entity_manager = \Drupal::entityTypeManager();
+    $entity_type_manager = \Drupal::entityTypeManager();
     $target_type = $this->getFieldSetting('target_type');
 
     $item_mode = isset($widget_state['paragraphs'][$delta]['mode']) ? $widget_state['paragraphs'][$delta]['mode'] : 'edit';
@@ -265,10 +260,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     }
     elseif (isset($widget_state['selected_bundle'])) {
 
-      $entity_type = $entity_manager->getDefinition($target_type);
+      $entity_type = $entity_type_manager->getDefinition($target_type);
       $bundle_key = $entity_type->getKey('bundle');
 
-      $paragraphs_entity = $entity_manager->getStorage($target_type)->create(array(
+      $paragraphs_entity = $entity_type_manager->getStorage($target_type)->create(array(
         $bundle_key => $widget_state['selected_bundle'],
       ));
       $paragraphs_entity->setParentEntity($items->getEntity(), $field_name);
@@ -401,8 +396,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         $actions = array();
         $links = array();
 
+        // Avoid checking delete access for new entities.
+        $delete_access = $paragraphs_entity->isNew() || $paragraphs_entity->access('delete');
         // Hide the button when translating.
-        $button_access = $paragraphs_entity->access('delete') && !$this->isTranslating;
+        $button_access = $delete_access && !$this->isTranslating;
         if ($item_mode != 'remove') {
           $links['remove_button'] = [
             '#type' => 'submit',
@@ -418,7 +415,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
               'effect' => 'fade',
             ],
             '#access' => $button_access,
-            '#prefix' => '<li class="remove">',
+            '#prefix' => '<li class="remove dropbutton__item  dropbutton__item--extrasmall">',
             '#suffix' => '</li>',
             '#paragraphs_mode' => 'remove',
           ];
@@ -442,7 +439,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
                 'effect' => 'fade',
               ),
               '#access' => $paragraphs_entity->access('update'),
-              '#prefix' => '<li class="collapse">',
+              '#prefix' => '<li class="collapse dropbutton__item  dropbutton__item--extrasmall">',
               '#suffix' => '</li>',
               '#paragraphs_mode' => 'collapsed',
               '#paragraphs_show_warning' => TRUE,
@@ -453,21 +450,21 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'),
+            '#access' => !$paragraphs_entity->access('update') && $delete_access,
           );
 
           $info['remove_button_info'] = array(
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'),
+            '#access' => !$delete_access && $paragraphs_entity->access('update'),
           );
 
           $info['edit_remove_button_info'] = array(
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'),
+            '#access' => !$paragraphs_entity->access('update') && !$delete_access,
           );
         }
         elseif ($item_mode == 'preview' || $item_mode == 'closed') {
@@ -485,7 +482,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
               'effect' => 'fade',
             ),
             '#access' => $paragraphs_entity->access('update'),
-            '#prefix' => '<li class="edit">',
+            '#prefix' => '<li class="edit dropbutton__item  dropbutton__item--extrasmall">',
             '#suffix' => '</li>',
             '#paragraphs_mode' => 'edit',
           );
@@ -509,21 +506,21 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'),
+            '#access' => !$paragraphs_entity->access('update') && $delete_access,
           );
 
           $info['remove_button_info'] = array(
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'),
+            '#access' => !$delete_access && $paragraphs_entity->access('update'),
           );
 
           $info['edit_remove_button_info'] = array(
             '#type' => 'container',
             '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))),
             '#attributes' => ['class' => ['messages', 'messages--warning']],
-            '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'),
+            '#access' => !$paragraphs_entity->access('update') && !$delete_access,
           );
         }
         elseif ($item_mode == 'remove') {
@@ -545,7 +542,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
               'wrapper' => $widget_state['ajax_wrapper_id'],
               'effect' => 'fade',
             ],
-            '#prefix' => '<li class="confirm-remove">',
+            '#prefix' => '<li class="confirm-remove dropbutton__item  dropbutton__item--extrasmall">',
             '#suffix' => '</li>',
             '#paragraphs_mode' => 'removed',
           ];
@@ -563,13 +560,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
               'wrapper' => $widget_state['ajax_wrapper_id'],
               'effect' => 'fade',
             ],
-            '#prefix' => '<li class="restore">',
+            '#prefix' => '<li class="restore dropbutton__item  dropbutton__item--extrasmall">',
             '#suffix' => '</li>',
             '#paragraphs_mode' => 'edit',
           ];
         }
 
-        if (count($links)) {
+        if (!empty($links)) {
           $show_links = 0;
           foreach($links as $link_item) {
             if (!isset($link_item['#access']) || $link_item['#access']) {
@@ -583,7 +580,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
             if ($show_links > 1) {
               $element['top']['links']['#theme_wrappers'] = array('dropbutton_wrapper', 'paragraphs_dropbutton_wrapper');
               $element['top']['links']['prefix'] = array(
-                '#markup' => '<ul class="dropbutton">',
+                '#markup' => '<ul class="dropbutton dropbutton--multiple dropbutton--extrasmall">',
                 '#weight' => -999,
               );
               $element['top']['links']['suffix'] = array(
@@ -602,7 +599,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
           }
         }
 
-        if (count($info)) {
+        if (!empty($info)) {
           $show_info = FALSE;
           foreach($info as $info_item) {
             if (!isset($info_item['#access']) || $info_item['#access']) {
@@ -617,7 +614,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
           }
         }
 
-        if (count($actions)) {
+        if (!empty($actions)) {
           $show_actions = FALSE;
           foreach($actions as $action_item) {
             if (!isset($action_item['#access']) || $action_item['#access']) {
@@ -648,7 +645,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         ];
 
         field_group_attach_groups($element['subform'], $context);
-        $element['subform']['#pre_render'][] = 'field_group_form_pre_render';
+        if (function_exists('field_group_form_pre_render')) {
+          $element['subform']['#pre_render'][] = 'field_group_form_pre_render';
+        }
+        if (function_exists('field_group_form_process')) {
+          $element['subform']['#process'][] = 'field_group_form_process';
+        }
       }
 
       if ($item_mode == 'edit') {
@@ -690,20 +692,19 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         }
       }
       elseif ($item_mode == 'preview') {
+        $view_builder = $entity_type_manager->getViewBuilder($paragraphs_entity->getEntityTypeId());
         $element['subform'] = array();
         $element['behavior_plugins'] = [];
-        $element['preview'] = entity_view($paragraphs_entity, 'preview', $paragraphs_entity->language()->getId());
+        $element['preview'] = $view_builder->view($paragraphs_entity, 'preview', $paragraphs_entity->language()->getId());
         $element['preview']['#access'] = $paragraphs_entity->access('view');
       }
       elseif ($item_mode == 'closed') {
         $element['subform'] = array();
         $element['behavior_plugins'] = [];
         if ($paragraphs_entity) {
-          $summary = $paragraphs_entity->getSummary();
           $element['top']['paragraph_summary']['fields_info'] = [
-            '#markup' => $summary,
-            '#prefix' => '<div class="paragraphs-collapsed-description">',
-            '#suffix' => '</div>',
+            '#theme' => 'paragraphs_summary',
+            '#summary' => $paragraphs_entity->getSummaryItems(),
           ];
         }
       }
@@ -766,7 +767,6 @@ public function getAllowedTypes() {
       }
     }
 
-
     return $return_bundles;
   }
 
@@ -1004,6 +1004,7 @@ protected function getAccessibleOptions() {
     $access_control_handler = $entity_type_manager->getAccessControlHandler($target_type);
     $dragdrop_settings = $this->getSelectionHandlerSetting('target_bundles_drag_drop');
 
+    $this->accessOptions = [];
     foreach ($bundles as $machine_name => $bundle) {
       if ($dragdrop_settings || (empty($this->getSelectionHandlerSetting('target_bundles'))
           || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles')))) {
@@ -1036,7 +1037,7 @@ protected function buildButtonsAddMode() {
       $drop_button = TRUE;
       $add_more_elements['#theme_wrappers'] = ['dropbutton_wrapper'];
       $add_more_elements['prefix'] = [
-        '#markup' => '<ul class="dropbutton">',
+        '#markup' => '<ul class="dropbutton dropbutton--multiple dropbutton--extrasmall">',
         '#weight' => -999,
       ];
       $add_more_elements['suffix'] = [
@@ -1063,7 +1064,7 @@ protected function buildButtonsAddMode() {
       ];
 
       if ($drop_button) {
-        $add_more_elements['add_more_button_' . $machine_name]['#prefix'] = '<li>';
+        $add_more_elements['add_more_button_' . $machine_name]['#prefix'] = '<li class="dropbutton__item dropbutton__item--extrasmall">';
         $add_more_elements['add_more_button_' . $machine_name]['#suffix'] = '</li>';
       }
     }
@@ -1328,7 +1329,8 @@ public function massageFormValues(array $values, array $form, FormStateInterface
       }
       // If our mode is remove don't save or reference this entity.
       // @todo: Maybe we should actually delete it here?
-      elseif($widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'remove' || $widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'removed') {
+      elseif(isset($widget_state['paragraphs'][$item['_original_delta']]['mode'])
+        && in_array($widget_state['paragraphs'][$item['_original_delta']]['mode'], ['remove', 'removed'])) {
         $item['target_id'] = NULL;
         $item['target_revision_id'] = NULL;
       }
diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
index 4a2c63d527..7c2a7070c1 100644
--- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
+++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
@@ -341,7 +341,7 @@ public function settingsSummary() {
     }
     $features_labels = array_intersect_key($this->getSettingOptions('features'), array_filter($this->getSetting('features')));
     if (!empty($features_labels)) {
-      $summary[] = $this->t('Features: @features', ['@features' => implode($features_labels, ', ')]);
+      $summary[] = $this->t('Features: @features', ['@features' => implode(', ', $features_labels)]);
     }
 
     return $summary;
@@ -437,7 +437,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       else {
         // If the node is being translated, the paragraphs should be all open
         // when the form is not being rebuilt (E.g. when clicked on a paragraphs
-        // action) and when the the translation is being added.
+        // action) and when the translation is being added.
         if (!$form_state->isRebuilding() && $host->getTranslationStatus($langcode) == TranslationStatusInterface::TRANSLATION_CREATED) {
           $item_mode = 'edit';
         }
@@ -603,6 +603,11 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
           '#access' => $this->duplicateButtonAccess($paragraphs_entity),
         ];
 
+        // Force the closed mode when the user cannot edit the Paragraph.
+        if (!$paragraphs_entity->access('update')) {
+          $item_mode = 'closed';
+        }
+
         if ($item_mode != 'remove') {
           $widget_actions['dropdown_actions']['remove_button'] = [
             '#type' => 'submit',
@@ -640,7 +645,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
               '#paragraphs_mode' => 'closed',
               '#paragraphs_show_warning' => TRUE,
               '#attributes' => [
-                'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse'],
+                'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse', 'button--extrasmall'],
                 'title' => $this->t('Collapse'),
               ],
             ];
@@ -664,7 +669,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
             '#access' => $paragraphs_entity->access('update') && !$translating_force_close,
             '#paragraphs_mode' => 'edit',
             '#attributes' => [
-              'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit'],
+              'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit', 'button--extrasmall'],
               'title' => $this->t('Edit'),
             ],
           ]);
@@ -677,10 +682,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
             ];
           }
 
-          if (!$paragraphs_entity->access('view')) {
+          if (!$paragraphs_entity->isPublished()) {
             $info['preview'] = [
               '#theme' => 'paragraphs_info_icon',
-              '#message' => $this->t('You are not allowed to view this @title.', array('@title' => $this->getSetting('title'))),
+              '#message' => $this->t('Unpublished'),
               '#icon' => 'view',
             ];
           }
@@ -696,14 +701,16 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
           ];
         }
 
-        if (!$paragraphs_entity->access('update') && $paragraphs_entity->access('delete')) {
+        // Avoid checking delete access for new entities.
+        $delete_access = $paragraphs_entity->isNew() || $paragraphs_entity->access('delete');
+        if (!$paragraphs_entity->access('update') && $delete_access) {
           $info['edit'] = [
             '#theme' => 'paragraphs_info_icon',
             '#message' => $this->t('You are not allowed to edit this @title.', ['@title' => $this->getSetting('title')]),
             '#icon' => 'edit-disabled',
           ];
         }
-        elseif (!$paragraphs_entity->access('delete') && $paragraphs_entity->access('update')) {
+        elseif (!$delete_access && $paragraphs_entity->access('update')) {
           $info['remove'] = [
             '#theme' => 'paragraphs_info_icon',
             '#message' => $this->t('You are not allowed to remove this @title.', ['@title' => $this->getSetting('title')]),
@@ -726,13 +733,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         // Allow modules to alter widget actions.
         \Drupal::moduleHandler()->alter('paragraphs_widget_actions', $widget_actions, $context);
 
-        if (count($widget_actions['actions'])) {
+        if (!empty($widget_actions['actions'])) {
           // Expand all actions to proper submit elements and add it to top
           // actions sub component.
           $element['top']['actions']['actions'] = array_map([$this, 'expandButton'], $widget_actions['actions']);
         }
 
-        if (count($widget_actions['dropdown_actions'])) {
+        if (!empty($widget_actions['dropdown_actions'])) {
           // Expand all dropdown actions to proper submit elements and add
           // them to top dropdown actions sub component.
           $element['top']['actions']['dropdown_actions'] = array_map([$this, 'expandButton'], $widget_actions['dropdown_actions']);
@@ -753,13 +760,29 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         ];
 
         field_group_attach_groups($element['subform'], $context);
-        $element['subform']['#pre_render'][] = 'field_group_form_pre_render';
+        if (function_exists('field_group_form_pre_render')) {
+          $element['subform']['#pre_render'][] = 'field_group_form_pre_render';
+        }
+        if (function_exists('field_group_form_process')) {
+          $element['subform']['#process'][] = 'field_group_form_process';
+        }
       }
 
       if ($item_mode == 'edit') {
         $display->buildForm($paragraphs_entity, $element['subform'], $form_state);
         $hide_untranslatable_fields = $paragraphs_entity->isDefaultTranslationAffectedOnly();
 
+        $summary = $paragraphs_entity->getSummaryItems();
+        if (!empty($summary)) {
+          $element['top']['summary']['fields_info'] = [
+            '#theme' => 'paragraphs_summary',
+            '#summary' => $summary,
+            '#expanded' => TRUE,
+            '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'),
+          ];
+        }
+        $info = array_merge($info, $paragraphs_entity->getIcons());
+
         foreach (Element::children($element['subform']) as $field) {
           if ($paragraphs_entity->hasField($field)) {
             $field_definition = $paragraphs_entity->get($field)->getFieldDefinition();
@@ -780,6 +803,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
 
             if (!$is_paragraph_field) {
               $element['subform'][$field]['#attributes']['class'][] = 'paragraphs-content';
+              $element['top']['summary']['fields_info'] = [
+                '#theme' => 'paragraphs_summary',
+                '#summary' => $summary,
+                '#expanded' => TRUE,
+                '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'),
+              ];
             }
             $translatable = $field_definition->isTranslatable();
             // Hide untranslatable fields when configured to do so except
@@ -831,12 +860,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
         else {
           // The closed paragraph is displayed as a summary.
           if ($paragraphs_entity) {
-            $summary = $paragraphs_entity->getSummary();
+            $summary = $paragraphs_entity->getSummaryItems();
             if (!empty($summary)) {
               $element['top']['summary']['fields_info'] = [
-                '#markup' => $summary,
-                '#prefix' => '<div class="paragraphs-collapsed-description">',
-                '#suffix' => '</div>',
+                '#theme' => 'paragraphs_summary',
+                '#summary' => $summary,
+                '#expanded' => FALSE,
                 '#access' => $paragraphs_entity->access('update') || $paragraphs_entity->access('view'),
               ];
             }
@@ -850,7 +879,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       }
 
       // If we have any info items lets add them to the top section.
-      if (count($info)) {
+      if (!empty($info)) {
         foreach ($info as $info_item) {
           if (!isset($info_item['#access']) || $info_item['#access']) {
             $element['top']['icons']['items'] = $info;
@@ -898,6 +927,7 @@ protected function buildModalAddForm(array &$element) {
         'class' => [
           'paragraph-type-add-modal',
           'first-button',
+          'paragraphs-add-wrapper',
         ],
       ],
       '#access' => $this->allowReferenceChanges(),
@@ -962,7 +992,7 @@ public function getAllowedTypes(FieldDefinitionInterface $field_definition = NUL
       $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($field_definition ? $field_definition->getSetting('target_type') : $this->fieldDefinition->getSetting('target_type'));
       $weight = 0;
       foreach ($bundles as $machine_name => $bundle) {
-        if (!count($this->getSelectionHandlerSetting('target_bundles'))
+        if (empty($this->getSelectionHandlerSetting('target_bundles'))
           || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles'))) {
 
           $return_bundles[$machine_name] = array(
@@ -975,7 +1005,6 @@ public function getAllowedTypes(FieldDefinitionInterface $field_definition = NUL
       }
     }
 
-
     return $return_bundles;
   }
 
@@ -1034,7 +1063,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
     $field_prefix = strtr($this->fieldIdPrefix, '_', '-');
     if (count($this->fieldParents) == 0) {
       if ($items->getEntity()->getEntityTypeId() != 'paragraph') {
-        $tabs = '<ul class="paragraphs-tabs tabs primary clearfix"><li id="content" class="tabs__tab"><a href="#' . $field_prefix . '-values">Content</a></li><li id="behavior" class="tabs__tab"><a href="#' . $field_prefix . '-values">Behavior</a></li></ul>';
+        $tabs = '<ul class="paragraphs-tabs tabs primary clearfix"><li id="content" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Content', [], ['context' => 'paragraphs']) . '</a></li><li id="behavior" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Behavior', [], ['context' => 'paragraphs']) . '</a></li></ul>';
       }
     }
     if (count($this->fieldParents) > 0) {
@@ -1060,6 +1089,9 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
           'callback' => [get_class($this), 'dragDropModeAjax'],
           'wrapper' => $this->fieldWrapperId,
         ],
+        '#limit_validation_errors' => [
+          array_merge($this->fieldParents, [$field_name]),
+        ],
         '#button_type' => 'primary',
       ]);
 
@@ -1158,6 +1190,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
     }
 
     $elements['#allow_reference_changes'] = $this->allowReferenceChanges();
+    $elements['#paragraphs_widget'] = TRUE;
     $elements['#attached']['library'][] = 'paragraphs/drupal.paragraphs.widget';
 
     return $elements;
@@ -1279,7 +1312,7 @@ protected function buildNestedParagraphsFoDragDrop(FormStateInterface $form_stat
     foreach ($field_definitions as $child_field_name => $field_definition) {
       $child_path = implode('][', array_merge($array_parents, [$child_field_name]));
       $cardinality = $field_definition->getFieldStorageDefinition()->getCardinality();
-      $allowed_types = implode(array_keys($this->getAllowedTypes($field_definition)), ',');
+      $allowed_types = implode(',', array_keys($this->getAllowedTypes($field_definition)));
       $elements[$child_field_name] = [
         '#type' => 'container',
         '#attributes' => ['class' => ['paragraphs-dragdrop-wrapper']],
@@ -1340,9 +1373,9 @@ protected function buildNestedParagraphsFoDragDrop(FormStateInterface $form_stat
         }
 
         $element['top']['summary']['fields_info'] = [
-          '#markup' => $child_paragraph->getSummary($summary_options),
-          '#prefix' => '<div class="paragraphs-collapsed-description">',
-          '#suffix' => '</div>',
+          '#theme' => 'paragraphs_summary',
+          '#summary' => $child_paragraph->getSummaryItems($summary_options),
+          '#expanded' => FALSE,
           '#access' => $child_paragraph->access('update') || $child_paragraph->access('view'),
         ];
 
@@ -1520,7 +1553,7 @@ public static function getSubmitElementInfo(array $form, FormStateInterface $for
   protected function buildDropbutton(array $elements = []) {
     $build = [
       '#type' => 'container',
-      '#attributes' => ['class' => ['paragraphs-dropbutton-wrapper']],
+      '#attributes' => ['class' => ['paragraphs-dropbutton-wrapper', 'paragraphs-add-wrapper']],
     ];
 
     $operations = [];
@@ -1555,15 +1588,13 @@ protected function buildButtonsAddMode() {
     $add_mode = $this->getSetting('add_mode');
     $paragraphs_type_storage = \Drupal::entityTypeManager()->getStorage('paragraphs_type');
 
-    // Build the buttons.
-    $add_more_elements = [];
     foreach ($options as $machine_name => $label) {
       $button_key = 'add_more_button_' . $machine_name;
       $add_more_elements[$button_key] = $this->expandButton([
         '#type' => 'submit',
         '#name' => $this->fieldIdPrefix . '_' . $machine_name . '_add_more',
         '#value' => $add_mode == 'modal' ? $label : $this->t('Add @type', ['@type' => $label]),
-        '#attributes' => ['class' => ['field-add-more-submit']],
+        '#attributes' => ['class' => ['field-add-more-submit', 'paragraphs-add-wrapper']],
         '#limit_validation_errors' => [array_merge($this->fieldParents, [$this->fieldDefinition->getName(), 'add_more'])],
         '#submit' => [[get_class($this), 'addMoreSubmit']],
         '#ajax' => [
@@ -1585,7 +1616,7 @@ protected function buildButtonsAddMode() {
     }
     elseif ($add_mode == 'modal') {
       $this->buildModalAddForm($add_more_elements);
-      $add_more_elements['add_modal_form_area']['#suffix'] = $this->t('to %type', ['%type' => $this->fieldDefinition->getLabel()]);
+      $add_more_elements['add_modal_form_area']['#suffix'] = '<span class="paragraphs-add-suffix">' . $this->t('to %type', ['%type' => $this->fieldDefinition->getLabel()]) . '</span>';
     }
     $add_more_elements['#weight'] = 1;
 
@@ -1602,13 +1633,28 @@ protected function buildSelectAddMode() {
     $field_name = $this->fieldDefinition->getName();
     $field_title = $this->fieldDefinition->getLabel();
     $setting_title = $this->getSetting('title');
+    $select_options = $this->getAccessibleOptions();
+
+    $add_more_elements = [
+      '#type' => 'container',
+      '#attributes' => [
+        'class' => ['paragraphs-add-wrapper'],
+      ],
+    ];
+
     $add_more_elements['add_more_select'] = [
       '#type' => 'select',
-      '#options' => $this->getAccessibleOptions(),
+      '#options' => $select_options,
       '#title' => $this->t('@title type', ['@title' => $setting_title]),
       '#label_display' => 'hidden',
     ];
 
+    // Do not present the select element if only one option is available.
+    if (count($select_options) === 1) {
+      $add_more_elements['add_more_select']['#type'] = 'value';
+      $add_more_elements['add_more_select']['#value'] = key($select_options);
+    }
+
     $text = $this->t('Add @title', ['@title' => $setting_title]);
 
     if ($this->realItemCount > 0) {
@@ -1645,6 +1691,13 @@ public static function addMoreAjax(array $form, FormStateInterface $form_state)
     $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
     $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
 
+    // Clear the Add more delta.
+    NestedArray::setValue(
+      $element,
+      ['add_more', 'add_modal_form_area', 'add_more_delta', '#value'],
+      ''
+    );
+
     return $element;
   }
 
@@ -1771,7 +1824,7 @@ public static function duplicateSubmit(array $form, FormStateInterface $form_sta
 
     // Check if the replicate module is enabled.
     if (\Drupal::hasService('replicate.replicator')) {
-      $duplicate_entity = \Drupal::getContainer()->get('replicate.replicator')->replicateEntity($entity);
+      $duplicate_entity = \Drupal::getContainer()->get('replicate.replicator')->cloneEntity($entity);
     }
     else {
       $duplicate_entity = $entity->createDuplicate();
@@ -2210,20 +2263,27 @@ public function massageFormValues(array $values, array $form, FormStateInterface
 
         // We can only use the entity form display to display validation errors
         // if it is in edit mode.
-        if ($widget_state['paragraphs'][$item['_original_delta']]['mode'] === 'edit') {
+        if (!$form_state->isValidationComplete() && $widget_state['paragraphs'][$item['_original_delta']]['mode'] === 'edit') {
           $display->validateFormValues($paragraphs_entity, $element[$item['_original_delta']]['subform'], $form_state);
         }
         // Assume that the entity is being saved/previewed, in this case,
         // validate even the closed paragraphs. If there are validation errors,
         // add them on the parent level. Validation errors do not rebuild the
         // form so it's not possible to auto-uncollapse the form at this point.
-        elseif ($form_state->getLimitValidationErrors() === NULL) {
+        elseif (!$form_state->isValidationComplete() && $form_state->getLimitValidationErrors() === NULL) {
           $violations = $paragraphs_entity->validate();
           $violations->filterByFieldAccess();
-          if (count($violations)) {
+          if (!empty($violations)) {
+            /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */
             foreach ($violations as $violation) {
-              /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */
-              $form_state->setError($element[$item['_original_delta']], $violation->getMessage());
+
+              // Ignore text format related validation errors by ignoring
+              // the .format property.
+              if (substr($violation->getPropertyPath(), -7) === '.format') {
+                continue;
+              }
+
+              $form_state->setError($element[$item['_original_delta']], $this->t('Validation error on collapsed paragraph @path: @message', ['@path' => $violation->getPropertyPath(), '@message' => $violation->getMessage()]));
             }
           }
         }
@@ -2507,7 +2567,7 @@ public function buildHeaderActions(array $field_state, FormStateInterface $form_
       // order and with the right settings.
       if ($mode === 'closed') {
         $edit_all['#attributes'] = [
-          'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit'],
+          'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-edit', 'button--extrasmall'],
           'title' => $this->t('Edit all'),
         ];
         $edit_all['#title'] = $this->t('Edit All');
@@ -2516,7 +2576,7 @@ public function buildHeaderActions(array $field_state, FormStateInterface $form_
       }
       else {
         $collapse_all['#attributes'] = [
-          'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse'],
+          'class' => ['paragraphs-icon-button', 'paragraphs-icon-button-collapse', 'button--extrasmall'],
           'title' => $this->t('Collapse all'),
         ];
         $actions['actions']['collapse_all'] = $collapse_all;
@@ -2610,7 +2670,8 @@ protected function allowReferenceChanges() {
    *   TRUE if we can remove paragraph, otherwise FALSE.
    */
   protected function removeButtonAccess(ParagraphInterface $paragraph) {
-    if (!$paragraph->access('delete')) {
+    // Avoid checking delete access for new entities.
+    if (!$paragraph->isNew() && !$paragraph->access('delete')) {
       return FALSE;
     }
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
index c21997bd83..19d9a21e4d 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
@@ -28,32 +28,6 @@ class FieldCollection extends FieldPluginBase {
    */
   const FIELD_COLLECTION_PREFIX_LENGTH = 6;
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processFieldFormatter(MigrationInterface $migration) {
-    $this->addViewModeProcess($migration);
-
-    // Workaround for Drupal 8.4. In D8.5+ this should only call the parent.
-    // @todo Remove all but parent call after Drupal 8.6 is released.
-    // @see https://www.drupal.org/project/paragraphs/issues/2950492
-    //
-    // Core issue:
-    // @see https://www.drupal.org/project/drupal/issues/2843617
-    $process = $migration->getProcess();
-    if (is_array($process['options/type'][0]['source'])) {
-      // Backwards compatibility with D8.5.
-      // @todo replace with parent::alterFieldFormatterMigration
-      // @see https://www.drupal.org/project/paragraphs/issues/2994933
-      // @see https://www.drupal.org/node/2944598
-      parent::processFieldFormatter($migration);
-    }
-    else {
-      $options_type[0]['map']['field_collection_view'] = 'entity_reference_revisions_entity_view';
-      $migration->mergeProcessOfProperty('options/type', $options_type);
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -80,13 +54,6 @@ public function getFieldWidgetMap() {
       + parent::getFieldWidgetMap();
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processField(MigrationInterface $migration) {
-    $this->alterFieldMigration($migration);
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -99,13 +66,6 @@ public function alterFieldMigration(MigrationInterface $migration) {
     $migration->mergeProcessOfProperty('settings', $settings);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processFieldInstance(MigrationInterface $migration) {
-    $this->alterFieldInstanceMigration($migration);
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
index cf7f1ee131..bb3d82121c 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
@@ -23,18 +23,6 @@
  */
 class Paragraphs extends FieldPluginBase {
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processFieldWidget(MigrationInterface $migration) {
-    // Backwards compatibility with D8.5.
-    // @todo replace with parent::alterFieldWidgetMigration
-    // @see https://www.drupal.org/project/paragraphs/issues/2994933
-    // @see https://www.drupal.org/node/2944598
-    parent::processFieldWidget($migration);
-    $this->paragraphAlterFieldWidgetMigration($migration);
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -43,32 +31,6 @@ public function alterFieldWidgetMigration(MigrationInterface $migration) {
     $this->paragraphAlterFieldWidgetMigration($migration);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processFieldFormatter(MigrationInterface $migration) {
-    $this->addViewModeProcess($migration);
-
-    // Workaround for Drupal 8.4. In D8.5+ this should only call the parent.
-    // @todo Remove all but parent call after Drupal 8.6 is released.
-    // @see https://www.drupal.org/project/paragraphs/issues/2950492
-    //
-    // Core issue:
-    // @see https://www.drupal.org/project/drupal/issues/2843617
-    $process = $migration->getProcess();
-    if (is_array($process['options/type'][0]['source'])) {
-      // Backwards compatibility with D8.5.
-      // @todo replace with parent::alterFieldFormatterMigration
-      // @see https://www.drupal.org/project/paragraphs/issues/2994933
-      // @see https://www.drupal.org/node/2944598
-      parent::processFieldFormatter($migration);
-    }
-    else {
-      $options_type[0]['map']['paragraphs_view'] = 'entity_reference_revisions_entity_view';
-      $migration->mergeProcessOfProperty('options/type', $options_type);
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -95,13 +57,6 @@ public function getFieldWidgetMap() {
       + parent::getFieldWidgetMap();
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processField(MigrationInterface $migration) {
-    $this->alterFieldMigration($migration);
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -115,13 +70,6 @@ public function alterFieldMigration(MigrationInterface $migration) {
     $migration->mergeProcessOfProperty('settings', $settings);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processFieldInstance(MigrationInterface $migration) {
-    $this->alterFieldInstanceMigration($migration);
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php b/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php
index 9a04e29841..ff56d9e8ef 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/process/ProcessPluginBase.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\paragraphs\Plugin\migrate\process;
 
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Component\Plugin\ConfigurableInterface;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -12,7 +12,7 @@
 /**
  * Base class for Paragraphs process plugins.
  */
-abstract class ProcessPluginBase extends MigrateProcessPluginBase implements ConfigurablePluginInterface, ContainerFactoryPluginInterface {
+abstract class ProcessPluginBase extends MigrateProcessPluginBase implements ConfigurableInterface, ContainerFactoryPluginInterface {
 
   /**
    * The entity bundle info service.
@@ -63,11 +63,4 @@ public function defaultConfiguration() {
     return [];
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function calculateDependencies() {
-    return [];
-  }
-
 }
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php b/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php
index 641ac491ea..c1a1b9ffed 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/DrupalSqlBase.php
@@ -2,10 +2,10 @@
 
 namespace Drupal\paragraphs\Plugin\migrate\source;
 
+use Drupal\Component\Plugin\ConfigurableInterface;
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase as MigrateDrupalSqlBase;
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\migrate\Plugin\MigrationInterface;
 
@@ -15,13 +15,13 @@
  * Add and implement Configurable Plugin interface to
  * Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase.
  */
-abstract class DrupalSqlBase extends MigrateDrupalSqlBase implements ConfigurablePluginInterface {
+abstract class DrupalSqlBase extends MigrateDrupalSqlBase implements ConfigurableInterface {
 
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_type_manager);
     $this->setConfiguration($configuration);
   }
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
index ea8dd8eba2..d96646be7b 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
@@ -58,8 +58,6 @@ public function query() {
    * {@inheritdoc}
    */
   public function prepareRow(Row $row) {
-    parent::prepareRow($row);
-
     // Remove field_ prefix for new bundle.
     $bundle = $row->getSourceProperty('field_name');
     $bundle = substr($bundle, FieldCollection::FIELD_COLLECTION_PREFIX_LENGTH);
@@ -74,6 +72,8 @@ public function prepareRow(Row $row) {
       $value = $this->getFieldValues('field_collection_item', $field_name, $item_id, $revision_id);
       $row->setSourceProperty($field_name, $value);
     }
+
+    return parent::prepareRow($row);
   }
 
   /**
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php
index 82587120c3..24dbdd63cc 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldableEntity.php
@@ -2,10 +2,10 @@
 
 namespace Drupal\paragraphs\Plugin\migrate\source\d7;
 
+use Drupal\Component\Plugin\ConfigurableInterface;
 use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity as MigrateFieldableEntity;
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\migrate\Plugin\MigrationInterface;
 
@@ -15,13 +15,13 @@
  * Add and implement Configurable Plugin interface to
  * Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity.
  */
-abstract class FieldableEntity extends MigrateFieldableEntity implements ConfigurablePluginInterface {
+abstract class FieldableEntity extends MigrateFieldableEntity implements ConfigurableInterface {
 
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_type_manager);
     $this->setConfiguration($configuration);
   }
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
index 49075a3745..5bd1f6f93f 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
@@ -78,7 +78,7 @@ public function fields() {
       'item_id' => $this->t('The paragraph_item id'),
       'revision_id' => $this->t('The paragraph_item revision id'),
       'bundle' => $this->t('The paragraph bundle'),
-      'field_name' => $this - t('The paragrpah field_name'),
+      'field_name' => $this->t('The paragraph field_name'),
     ];
 
     return $fields;
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php b/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php
index efa726fb48..031ecc54ad 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php
+++ b/web/modules/paragraphs/src/Tests/Classic/ParagraphsTestBase.php
@@ -3,12 +3,7 @@
 namespace Drupal\paragraphs\Tests\Classic;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\node\Entity\NodeType;
-use Drupal\paragraphs\Entity\ParagraphsType;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\simpletest\WebTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php b/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php
index 752b5de6b5..8542be2482 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php
+++ b/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTestBase.php
@@ -3,10 +3,7 @@
 namespace Drupal\paragraphs\Tests\Experimental;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\paragraphs\Tests\Classic\ParagraphsTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
diff --git a/web/modules/paragraphs/templates/paragraphs-summary.html.twig b/web/modules/paragraphs/templates/paragraphs-summary.html.twig
new file mode 100644
index 0000000000..b7f9330bbb
--- /dev/null
+++ b/web/modules/paragraphs/templates/paragraphs-summary.html.twig
@@ -0,0 +1,45 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a paragraphs summary.
+ *
+ * Available variables:
+ * - expanded: Whether the summary is expanded or not.
+ * - content: Array of content summary items.
+ * - behaviors: Array of behavior summary items.
+ *
+ * @see template_preprocess()
+ *
+ * @ingroup themeable
+ */
+#}
+{% set classes = [
+  'paragraphs-description',
+  expanded ? 'paragraphs-expanded-description' : 'paragraphs-collapsed-description'
+] %}
+{% spaceless %}
+  {% if content is not empty or behaviors is not empty %}
+    <div{{ attributes.addClass(classes) }}>
+      {% if content is not empty %}
+        <div class="paragraphs-content-wrapper">
+          {%- for content_item in content -%}
+            <span class="summary-content">{{ content_item }}</span>
+            {%- if not loop.last -%}, {% endif %}
+          {%- endfor -%}
+        </div>
+      {% endif %}
+      {% if behaviors is not empty %}
+        <div class="paragraphs-plugin-wrapper">
+          {%- for behavior_item in behaviors -%}
+            <span class="summary-plugin">
+              {%- if behavior_item.label is not null -%}
+                <span class="summary-plugin-label">{{ behavior_item.label }}</span>
+              {%- endif -%}
+              {{ behavior_item.value -}}
+            </span>
+          {%- endfor -%}
+        </div>
+      {% endif %}
+    </div>
+  {% endif %}
+{% endspaceless %}
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
index a78e17e5e3..094c654fc5 100644
--- a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
@@ -1,15 +1,14 @@
 name: Paragraphs test
 type: module
 description: Resources for Paragraphs tests
-# core: 8.x
+core_version_requirement: ^8.7.7 || ^9
 hidden: true
 package: Paragraphs
 
 dependencies:
-  - paragraphs
+  - paragraphs:paragraphs
 
-# Information added by Drupal.org packaging script on 2019-02-20
-version: '8.x-1.6'
-core: '8.x'
+# Information added by Drupal.org packaging script on 2020-02-16
+version: '8.x-1.11'
 project: 'paragraphs'
-datestamp: 1550669588
+datestamp: 1581850832
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php
index 376c522141..73b8c7fa35 100644
--- a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestBoldTextBehavior.php
@@ -61,7 +61,12 @@ public static function isApplicable(ParagraphsType $paragraphs_type) {
    */
   public function settingsSummary(Paragraph $paragraph) {
     $bold_setting = $paragraph->getBehaviorSetting($this->getPluginId(), 'bold_text');
-    return [$bold_setting ? $this->t('Bold: Yes') : $this->t('Bold: No')];
+    return [
+      [
+        'label' => $this->t('Bold'),
+        'value' => $bold_setting ? $this->t('Yes') : $this->t('No')
+      ]
+    ];
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php
index 16f0bd3d57..5966d8b149 100644
--- a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Plugin/paragraphs/Behavior/TestTextColorBehavior.php
@@ -97,6 +97,11 @@ public function view(array &$build, Paragraph $paragraphs_entity, EntityViewDisp
    */
   public function settingsSummary(Paragraph $paragraph) {
     $text_color = $paragraph->getBehaviorSetting($this->pluginId, 'text_color');
-    return [$this->t('Text color: @color', ['@color' => $text_color])];
+    return [
+      [
+        'label' => $this->t('Text color'),
+        'value' => $text_color
+      ]
+    ];
   }
 }
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php
similarity index 90%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php
index 78ba75f484..bc636570fc 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php
@@ -1,13 +1,12 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\image\Entity\ImageStyle;
 use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\user\RoleInterface;
-use Drupal\user\Entity\Role;
 
 /**
  * Tests the access check of paragraphs.
@@ -93,7 +92,7 @@ public function testParagraphAccessCheck() {
 
     // Remove the "access content" for anonymous users. That results in
     // anonymous users not being able to "view" the host entity.
-    /* @var Role $role */
+    /* @var \Drupal\user\Entity\Role $role */
     $role = \Drupal::entityTypeManager()
       ->getStorage('user_role')
       ->load(RoleInterface::ANONYMOUS_ID);
@@ -117,25 +116,31 @@ public function testParagraphAccessCheck() {
     // Add a new paragraphs images item.
     $this->drupalPostForm(NULL, NULL, t('Add images'));
 
-    $images = $this->drupalGetTestFiles('image');
+    $images = $this->getTestFiles('image');
 
+    $file_system = \Drupal::service('file_system');
     // Create a file, upload it.
-    file_unmanaged_copy($images[0]->uri, 'temporary://privateImage.jpg');
+    $file_system->copy($images[0]->uri, 'temporary://privateImage.jpg');
     $file_path = $this->container->get('file_system')
       ->realpath('temporary://privateImage.jpg');
 
     // Create a file, upload it.
-    file_unmanaged_copy($images[1]->uri, 'temporary://privateImage2.jpg');
+    $file_system->copy($images[1]->uri, 'temporary://privateImage2.jpg');
     $file_path_2 = $this->container->get('file_system')
       ->realpath('temporary://privateImage2.jpg');
 
     $edit = array(
       'title[0][value]' => 'Security test node',
-      'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => [$file_path, $file_path_2],
+      'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path,
     );
 
     $this->drupalPostForm(NULL, $edit, t('Upload'));
-    $this->drupalPostForm(NULL,  [], t('Preview'));
+
+    $edit = array(
+      'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2,
+    );
+
+    $this->drupalPostForm(NULL,  $edit, t('Preview'));
     $image_style = ImageStyle::load('medium');
     $img1_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage.jpg');
     $image_url = file_url_transform_relative($img1_url);
@@ -182,8 +187,8 @@ public function testParagraphAccessCheck() {
     // Check the remove button is present.
     $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]'));
     // Delete the Paragraph and save.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_remove');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_confirm_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_confirm_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $node = $this->getNodeByTitle('delete_permissions');
     $this->assertUrl('node/' . $node->id());
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php
similarity index 97%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php
index d8f24c6971..e934a77978 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAddModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\paragraphs\Entity\ParagraphsType;
 
 /**
@@ -12,8 +11,6 @@
  */
 class ParagraphsAddModesTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Tests that paragraphs field does not allow default values.
    */
@@ -125,7 +122,7 @@ protected function assertAddButtons($options) {
     $buttons = $this->xpath('//input[@class="field-add-more-submit button js-form-submit form-submit"]');
     // Check if the buttons are in the same order as the given array.
     foreach ($buttons as $key => $button) {
-      $this->assertEqual($button['value'], $options[$key]);
+      $this->assertEqual($button->getValue(), $options[$key]);
     }
     $this->assertTrue(count($buttons) == count($options), 'The amount of drop down options matches with the given array');
   }
@@ -143,7 +140,7 @@ protected function assertSelectOptions($options, $paragraphs_field) {
     $buttons = $this->xpath('//*[@name="' . $paragraphs_field . '[add_more][add_more_select]"]/option');
     // Check if the options are in the same order as the given array.
     foreach ($buttons as $key => $button) {
-      $this->assertEqual($button['value'], $options[$key]);
+      $this->assertEqual($button->getValue(), $options[$key]);
     }
     $this->assertTrue(count($buttons) == count($options), 'The amount of select options matches with the given array');
     $this->assertNotEqual($this->xpath('//*[@name="' . $paragraphs_field .'_add_more"]'), [], 'The add button is displayed');
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php
similarity index 84%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php
index 482b1e936a..08dc9184b1 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsAdministrationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\paragraphs\Entity\Paragraph;
 
 /**
@@ -12,8 +11,6 @@
  */
 class ParagraphsAdministrationTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -65,8 +62,8 @@ public function testParagraphsRevisions() {
 
     // Create node with our paragraphs.
     $this->drupalGet('node/add/paragraphs');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     $edit = [
       'title[0][value]' => 'TEST TITEL',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1',
@@ -144,7 +141,7 @@ public function testParagraphsCreation() {
 
     // Assert suggested 'Add a paragraph type' link when there is no type yet.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->assertText('There are no paragraphs type entities yet.');
+    $this->assertText('There are no Paragraphs types yet.');
     $this->drupalGet('admin/structure/types/manage/paragraphs/fields/add-field');
     $edit = [
       'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
@@ -180,7 +177,7 @@ public function testParagraphsCreation() {
 
     // Change the add more button to select mode.
     $this->clickLink(t('Manage form display'));
-    $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update'));
     $this->drupalPostForm(NULL, [], t('Save'));
 
@@ -209,7 +206,7 @@ public function testParagraphsCreation() {
     $field_name = 'field_paragraphs';
 
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit");
+    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
 
     // Enable setting.
     $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button');
@@ -219,7 +216,7 @@ public function testParagraphsCreation() {
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     $this->assertText('Add mode: Buttons', 'Checking the settings value.');
 
-    $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit");
+    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
     // Assert the 'Buttons' option is selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button', 'Updated value is correct!.');
 
@@ -229,11 +226,11 @@ public function testParagraphsCreation() {
     // Checking changes on article.
     $this->assertRaw('<div class="paragraphs-dropbutton-wrapper"><input', 'Updated value in article.');
 
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
 
     // Upload some images.
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
 
     $edit = array(
@@ -264,25 +261,25 @@ public function testParagraphsCreation() {
     // Test for closed setting.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Enable setting.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Check if the setting is stored.
     $this->assertText('Edit mode: Closed', 'Checking the settings value.');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Assert the 'Closed' option is selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Updated value correctly.');
     $this->drupalGet('node/1/edit');
     // The textareas for paragraphs should not be visible.
     $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]');
     $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 1, ' . $files[0]->filename);
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 2, ' . $files[1]->filename);
+    $this->assertRaw('<span class="summary-content">Test text 1</span>, <span class="summary-content">' . $files[0]->filename);
+    $this->assertRaw('<span class="summary-content">Test text 2</span>, <span class="summary-content">' . $files[1]->filename);
 
     // Test for preview option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('Edit mode: Preview', 'Checking the settings value.');
@@ -295,7 +292,7 @@ public function testParagraphsCreation() {
 
     // Test for open option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Assert the 'Preview' option is selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'preview', 'Updated value correctly.');
     // Restore the value to Open for next test.
@@ -317,19 +314,21 @@ public function testParagraphsCreation() {
     $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2');
     $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Remove 2nd paragraph.
-    $this->drupalPostForm(NULL, NULL, t('Remove'));
+    $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
+    // Confirm the removal.
+    $this->drupalPostForm(NULL, [], t('Confirm removal'));
     $this->assertNoField('field_paragraphs[1][subform][field_text][0][value]');
     $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Assert the paragraph is not deleted unless the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Remove the second paragraph.
-    $this->drupalPostForm(NULL, [], t('Remove'));
+    $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
+    // Confirm the removal.
+    $this->drupalPostForm(NULL, [], t('Confirm removal'));
     $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt',
-      'field_paragraphs[0][subform][field_image][0][width]' => 300,
-      'field_paragraphs[0][subform][field_image][0][height]' => 300,
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Assert the paragraph is deleted after the user saves the node.
@@ -375,11 +374,11 @@ public function testParagraphsCreation() {
 
     // Add a new article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_test_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
     // Test the new field is displayed.
     $this->assertFieldByName('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]');
 
@@ -399,7 +398,7 @@ public function testParagraphsCreation() {
     // Test that unsupported widgets are not displayed.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     $select = $this->xpath('//*[@id="edit-fields-field-paragraphs-type"]')[0];
-    $this->assertEqual(count($select->option), 2);
+    $this->assertCount(2, $select->findAll('css', 'option'));
     $this->assertRaw('value="entity_reference_paragraphs" selected="selected"');
 
     // Check that Paragraphs is not displayed as an entity_reference field
@@ -425,12 +424,12 @@ public function testParagraphsCreation() {
     ), array());
     $this->clickLink(t('Manage form display'));
     $this->drupalPostForm(NULL, [], 'Save');
-    $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
+    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
     $edit = array(
       'title[0][value]' => 'Nested twins',
     );
@@ -444,7 +443,7 @@ public function testParagraphsCreation() {
     $this->drupalPostForm(NULL, ['required' => FALSE], t('Save settings'));
 
     // Set the Paragraph field edit mode to 'Closed'.
-    $this->drupalPostAjaxForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'], t('Update'));
     $this->drupalPostForm(NULL, [], t('Save'));
 
@@ -461,7 +460,7 @@ public function testParagraphsCreation() {
     $node = $this->drupalGetNodeByTitle('Nested twins');
 
     // Create a node with a reference in a Paragraph.
-    $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
+    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
     \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
     $edit = [
       'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')',
@@ -483,7 +482,7 @@ public function testParagraphsCreation() {
     $this->assertText('The referenced entity (node: 4) does not exist');
     $this->assertText('Entity reference (value 1) field is required.');
     // Try to collapse with an invalid reference.
-    $this->drupalPostAjaxForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
     // Paragraph should be still in edit mode.
     $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][0][target_id]');
     $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][1][target_id]');
@@ -491,11 +490,11 @@ public function testParagraphsCreation() {
     // Assert the validation message.
     $this->assertText('There are no entities matching "foo".');
     // Attempt to remove the Paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]');
     $this->assertTrue(!empty($elements), "'Confirm removal' button appears.");
     // Restore the Paragraph and fix the broken reference.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_restore');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore');
     $node = $this->drupalGetNodeByTitle('Example publish/unpublish');
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
@@ -505,22 +504,22 @@ public function testParagraphsCreation() {
     $node->delete();
 
     // Set the Paragraph field edit mode to 'Preview'.
-    $this->drupalPostAjaxForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview'], t('Update'));
     $this->drupalPostForm(NULL, [], t('Save'));
 
     $node = $this->drupalGetNodeByTitle('choke test');
     // Attempt to edit the Paragraph.
-    $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_edit');
     // Try to save with an invalid reference.
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('There are no entities matching "foo".');
     // Remove the Paragraph and save the node.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]');
     $this->assertTrue(!empty($elements), "'Confirm removal' button appears.");
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_confirm_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('choke test has been updated.');
 
@@ -532,34 +531,7 @@ public function testParagraphsCreation() {
     $this->drupalGet('admin/content/files');
     $this->clickLink('1 place');
     $label = $this->xpath('//tbody/tr/td[1]');
-    $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->asXML()))), 'test required > field_paragraphs > Paragraphs');
-  }
-
-  /**
-   * Asserts that a select option in the current page is checked.
-   *
-   * @param string $id
-   *   ID of select field to assert.
-   * @param string $option
-   *   Option to assert.
-   * @param string $message
-   *   (optional) A message to display with the assertion. Do not translate
-   *   messages: use format_string() to embed variables in the message text, not
-   *   t(). If left blank, a default message will be displayed.
-   * @param string $group
-   *   (optional) The group this message is in, which is displayed in a column
-   *   in test output. Use 'Debug' to indicate this is debugging output. Do not
-   *   translate this string. Defaults to 'Browser'; most tests do not override
-   *   this default.
-   *
-   * @return bool
-   *   TRUE on pass, FALSE on fail.
-   *
-   * @todo Remove function once core issue is resolved: https://www.drupal.org/node/2530092
-   */
-  protected function assertOptionSelected($id, $option, $message = '', $group = 'Browser') {
-    $elements = $this->xpath('//select[contains(@id, :id)]//option[@value=:option]', array(':id' => $id, ':option' => $option));
-    return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : SafeMarkup::format('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), $group);
+    $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->getText()))), 'test required > field_paragraphs > Paragraphs');
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php
similarity index 98%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php
index 34b0e0f2d0..c8be65e788 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsClassicContentModerationTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php
@@ -1,13 +1,8 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -15,12 +10,8 @@
  *
  * @group paragraphs
  */
-class ParagraphsClassicContentModerationTranslationsTest extends BrowserTestBase {
+class ParagraphsClassicContentModerationTranslationsTest extends ParagraphsTestBase {
 
-  use LoginAdminTrait;
-  use FieldUiTestTrait;
-  use ParagraphsTestBaseTrait;
-  use ParagraphsCoreVersionUiTestTrait;
   use ParagraphsLastEntityQueryTrait;
 
   /**
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php
similarity index 97%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php
index 64945433e9..fbaa9db07c 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsConfigTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\NodeType;
@@ -51,7 +51,7 @@ public function testFieldTranslationDisabled() {
     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
 
     // Create a node with a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'paragraphs_field_paragraph_type_test_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'paragraphs_field_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'paragraphed_title'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
@@ -159,7 +159,7 @@ public function testRequiredParagraphsField() {
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('paragraphs field is required.');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('paragraphed_test test_title has been created.');
   }
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php
similarity index 85%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php
index 6ed36c0a07..58a26442e3 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsContactTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 use Drupal\contact\Entity\ContactForm;
 
@@ -40,10 +40,10 @@ public function testContactForm() {
 
     // Add a paragraph to the contact form.
     $this->drupalGet('contact/test_contact_form');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
     // Check that the paragraph is displayed.
     $this->assertText('paragraphs_contact');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'paragraphs_0_remove');
     $this->assertText('Deleted Paragraph: paragraphs_contact');
   }
 }
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php
similarity index 67%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php
index 821f02667b..e1529bb1ce 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEditModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php
@@ -1,8 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests paragraphs edit modes.
@@ -11,8 +9,6 @@
  */
 class ParagraphsEditModesTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -42,15 +38,15 @@ public function testCollapsedSummary() {
 
     // Set edit mode to closed.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit");
     $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
     // Add a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
 
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
 
     // Create a node with an image and text.
@@ -64,28 +60,26 @@ public function testCollapsedSummary() {
 
     // Assert the summary is correctly generated.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">' . $files[0]->filename . ', text_summary');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Title example');
+    $this->assertRaw('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>');
+    $this->assertRaw('<span class="summary-content">Title example');
 
     // Edit and remove alternative text.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary',
-      'field_paragraphs[0][subform][field_image][0][width]' => 300,
-      'field_paragraphs[0][subform][field_image][0][height]' => 300,
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     // Assert the summary is correctly generated.
-    $this->assertRaw('<div class="paragraphs-collapsed-description">alternative_text_summary, text_summary');
+    $this->assertRaw('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>');
 
     // Remove image.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
     $this->drupalPostForm(NULL, [], t('Save'));
 
     // Assert the summary is correctly generated.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">text_summary');
+    $this->assertRaw('<span class="summary-content">text_summary');
 
     // Add a Block Paragraphs type.
     $this->addParagraphsType('block_paragraph');
@@ -93,14 +87,14 @@ public function testCollapsedSummary() {
 
     // Test the summary of a Block field.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'Node with a Block Paragraph',
       'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'system_breadcrumb_block',
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Breadcrumbs');
+    $this->assertRaw('<span class="summary-content">Breadcrumbs');
   }
 
 }
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
similarity index 98%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
index 91c236a023..778866561c 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests the translation of heavily nested / specialized setup.
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php
similarity index 90%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php
index 2adee34a65..5a564815fb 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsFieldGroupTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests the field group on node.
@@ -48,13 +48,14 @@ public function testFieldGroup() {
 
     // Put the text field into the field group.
     $edit = [
+      'fields[group_field][region]' => 'content',
       'fields[field_text][parent]' => 'group_field'
     ];
     $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save'));
 
     // Create a node with a paragraph.
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostAjaxForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
 
     // Test if the new field group is displayed.
     $this->assertText('field_group');
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php
similarity index 92%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php
index 433a911421..4f07699de4 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsInlineEntityFormTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests the configuration of paragraphs in relation to ief.
@@ -52,7 +52,7 @@ public function testParagraphsIEFPreview() {
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -66,7 +66,7 @@ public function testParagraphsIEFPreview() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Try to open the previewed paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
   }
 
   /**
@@ -82,7 +82,6 @@ public function testParagraphsIEFChangeOrder() {
     $this->addParagraphsType('simple');
     $this->addParagraphsType('text');
 
-
     // Create a reference to an article.
     $this->fieldUIAddNewField('admin/structure/paragraphs_type/simple', 'article', 'Article', 'field_ui:entity_reference:node', [
       'settings[target_type]' => 'node',
@@ -113,7 +112,7 @@ public function testParagraphsIEFChangeOrder() {
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -128,7 +127,7 @@ public function testParagraphsIEFChangeOrder() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Create second paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values of second paragraph and change the order.
     $edit = [
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php
similarity index 87%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php
index b866c6b302..e2c2ec782a 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsPreviewTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php
@@ -1,8 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests the configuration of paragraphs.
@@ -11,8 +9,6 @@
  */
 class ParagraphsPreviewTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -45,7 +41,7 @@ public function testParagraphsPreview() {
     $test_text_2 = 'dummy_preview_text_2';
     // Create node with two paragraphs.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     // Set the value of the paragraphs.
     $edit = [
       'title[0][value]' => 'Page_title',
@@ -64,12 +60,12 @@ public function testParagraphsPreview() {
     $this->clickLink('Back to content editing');
 
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
-    $this->assertEqual($paragraph_1['value'], $test_text_1);
+    $this->assertEqual($paragraph_1->getValue(), $test_text_1);
 
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
     $this->clickLink('Edit');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     $edit = [
       'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2,
     ];
@@ -98,8 +94,8 @@ public function testParagraphsPreview() {
     $this->clickLink('Back to content editing');
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
     $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0];
-    $this->assertEqual($paragraph_1['value'], $test_text_1);
-    $this->assertEqual($paragraph_2['value'], $new_test_text_2);
+    $this->assertEqual($paragraph_1->getValue(), $test_text_1);
+    $this->assertEqual($paragraph_2->getValue(), $new_test_text_2);
     $this->drupalPostForm(NULL, [], t('Save'));
 
     $this->assertRaw($test_text_1);
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php
similarity index 88%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php
index 1d53a731ef..3790ca6a11 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsSummaryFormatterTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php
@@ -1,8 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests the paragraphs summary formatter.
@@ -11,8 +9,6 @@
  */
 class ParagraphsSummaryFormatterTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -48,8 +44,8 @@ public function testParagraphsSummaryFormatter() {
     $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Add a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
 
     // Create a node with a text.
     $edit = [
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php
new file mode 100644
index 0000000000..f053c3d903
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php
@@ -0,0 +1,208 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Functional\Classic;
+
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
+use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
+
+/**
+ * Base class for tests.
+ */
+abstract class ParagraphsTestBase extends BrowserTestBase {
+
+  use FieldUiTestTrait, ParagraphsCoreVersionUiTestTrait, ParagraphsTestBaseTrait;
+
+  /**
+   * Drupal user object created by loginAsAdmin().
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $admin_user = NULL;
+
+  /**
+   * List of permissions used by loginAsAdmin().
+   *
+   * @var array
+   */
+  protected $admin_permissions = [];
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'node',
+    'paragraphs',
+    'field',
+    'field_ui',
+    'block',
+    'paragraphs_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Place the breadcrumb, tested in fieldUIAddNewField().
+    $this->drupalPlaceBlock('system_breadcrumb_block');
+    $this->drupalPlaceBlock('local_tasks_block');
+    $this->drupalPlaceBlock('local_actions_block');
+    $this->drupalPlaceBlock('page_title_block');
+
+    $this->admin_permissions = [
+      'administer content types',
+      'administer node fields',
+      'administer paragraphs types',
+      'administer node form display',
+      'administer paragraph fields',
+      'administer paragraph form display',
+    ];
+  }
+
+  /**
+   * Creates an user with admin permissions and log in.
+   *
+   * @param array $additional_permissions
+   *   Additional permissions that will be granted to admin user.
+   * @param bool $reset_permissions
+   *   Flag to determine if default admin permissions will be replaced by
+   *   $additional_permissions.
+   *
+   * @return object
+   *   Newly created and logged in user object.
+   */
+  function loginAsAdmin($additional_permissions = [], $reset_permissions = FALSE) {
+    $permissions = $this->admin_permissions;
+
+    if ($reset_permissions) {
+      $permissions = $additional_permissions;
+    }
+    elseif (!empty($additional_permissions)) {
+      $permissions = array_merge($permissions, $additional_permissions);
+    }
+
+    $this->admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->admin_user);
+    return $this->admin_user;
+  }
+
+  /**
+   * Sets the Paragraphs widget add mode.
+   *
+   * @param string $content_type
+   *   Content type name where to set the widget mode.
+   * @param string $paragraphs_field
+   *   Paragraphs field to change the mode.
+   * @param string $mode
+   *   Mode to be set. ('dropdown', 'select' or 'button').
+   */
+  protected function setAddMode($content_type, $paragraphs_field, $mode) {
+    $form_display = EntityFormDisplay::load('node.' . $content_type . '.default')
+      ->setComponent($paragraphs_field, [
+        'type' => 'entity_reference_paragraphs',
+        'settings' => ['add_mode' => $mode]
+      ]);
+    $form_display->save();
+  }
+
+  /**
+   * Sets the allowed Paragraphs types that can be added.
+   *
+   * @param string $content_type
+   *   Content type name that contains the paragraphs field.
+   * @param array $paragraphs_types
+   *   Array of paragraphs types that will be modified.
+   * @param bool $selected
+   *   Whether or not the paragraphs types will be enabled.
+   * @param string $paragraphs_field
+   *   Paragraphs field name that does the reference.
+   */
+  protected function setAllowedParagraphsTypes($content_type, $paragraphs_types, $selected, $paragraphs_field) {
+    $edit = [];
+    $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/node.' . $content_type . '.' . $paragraphs_field);
+    foreach ($paragraphs_types as $paragraphs_type) {
+      $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][enabled]'] = $selected;
+    }
+    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+  }
+
+  /**
+   * Sets the weight of a given Paragraphs type.
+   *
+   * @param string $content_type
+   *   Content type name that contains the paragraphs field.
+   * @param string $paragraphs_type
+   *   ID of Paragraph type that will be modified.
+   * @param int $weight
+   *   Weight to be set.
+   * @param string $paragraphs_field
+   *   Paragraphs field name that does the reference.
+   */
+  protected function setParagraphsTypeWeight($content_type, $paragraphs_type, $weight, $paragraphs_field) {
+    $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/node.' . $content_type . '.' . $paragraphs_field);
+    $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][weight]'] = $weight;
+    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+  }
+
+  /**
+   * Sets the default paragraph type.
+   *
+   * @param $content_type
+   *   Content type name that contains the paragraphs field.
+   * @param $paragraphs_name
+   *   Paragraphs name.
+   * @param $paragraphs_field_name
+   *   Paragraphs field name to be used.
+   * @param $default_type
+   *   Default paragraph type which should be set.
+   */
+  protected function setDefaultParagraphType($content_type, $paragraphs_name, $paragraphs_field_name, $default_type) {
+    $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display');
+    $this->drupalPostForm(NULL, [], $paragraphs_field_name);
+    $this->drupalPostForm(NULL, ['fields[' . $paragraphs_name . '][settings_edit_form][settings][default_paragraph_type]' => $default_type], t('Update'));
+    $this->drupalPostForm(NULL, [], t('Save'));
+  }
+
+  /**
+   * Removes the default paragraph type.
+   *
+   * @param $content_type
+   *   Content type name that contains the paragraphs field.
+   */
+  protected function removeDefaultParagraphType($content_type) {
+    $this->drupalGet('node/add/' . $content_type);
+    $this->drupalPostForm(NULL, [], 'Remove');
+    $this->drupalPostForm(NULL, [], 'Confirm removal');
+    $this->assertNoText('No paragraphs added yet.');
+  }
+
+  /**
+   * Sets the Paragraphs widget display mode.
+   *
+   * @param string $content_type
+   *   Content type name where to set the widget mode.
+   * @param string $paragraphs_field
+   *   Paragraphs field to change the mode.
+   * @param string $mode
+   *   Mode to be set. ('closed', 'preview' or 'open').
+   *   'preview' is only allowed in the classic widget. Use
+   *   setParagraphsWidgetSettings for the experimental widget, instead.
+   */
+  protected function setParagraphsWidgetMode($content_type, $paragraphs_field, $mode) {
+    $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display');
+    $this->drupalPostForm(NULL, [], $paragraphs_field . '_settings_edit');
+    $this->drupalPostForm(NULL, ['fields[' . $paragraphs_field . '][settings_edit_form][settings][edit_mode]' => $mode], t('Update'));
+    $this->drupalPostForm(NULL, [], 'Save');
+  }
+
+}
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php
similarity index 96%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php
index bfddda5fc0..1cd2d009c2 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTranslationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -137,8 +137,8 @@ public function testParagraphTranslation() {
     $this->assertText(t('Example published and unpublished'));
     $this->clickLink(t('Edit'));
 
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'field_paragraphs_demo[0][subform][status][value]' => FALSE,
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text'
@@ -263,7 +263,7 @@ public function testParagraphTranslation() {
     $this->drupalPostForm(NULL, $edit, t('Save settings'));
 
     // Create a node with an image paragraph, its alt and title text.
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
     $file_path = $file_system->realpath($file_system->realpath($files[0]->uri));
     $this->drupalGet('node/add/paragraphed_content_demo');
@@ -435,7 +435,7 @@ public function testParagraphTranslationMultilingual() {
     $this->drupalPostForm(NULL, NULL, t('Add images'));
     $this->assertParagraphsButtons(1);
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
@@ -467,7 +467,7 @@ public function testParagraphTranslationMultilingual() {
 
     // Edit the french translation and upload a new image.
     $this->clickLink('Edit');
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ], t('Upload'));
@@ -499,12 +499,12 @@ public function testParagraphTranslationMultilingual() {
     $this->assertParagraphsButtons(2);
     // Add an 'Images' paragraph inside the nested one, check the paragraphs
     // langcode are still 'en' and the paragraphs buttons are still displayed.
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Upload a new image, check the paragraphs langcode are still 'en' and the
     // paragraphs buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[2];
+    $images = $this->getTestFiles('image')[2];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -548,7 +548,7 @@ public function testParagraphTranslationMultilingual() {
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
     // Upload another image.
-    $images = $this->drupalGetTestFiles('image')[3];
+    $images = $this->getTestFiles('image')[3];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ], t('Upload'));
@@ -577,12 +577,12 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id(), 'de');
     $this->assertParagraphsButtons(3);
     // Upload a new image, check the paragraphs langcode are still 'de' and the
     // paragraphs buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[4];
+    $images = $this->getTestFiles('image')[4];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -619,9 +619,9 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -637,7 +637,7 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'english' and upload another image.
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $edit = [
       'title[0][value]' => 'Title in german (en)',
       'langcode[0][value]' => 'en',
@@ -667,9 +667,9 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
@@ -691,13 +691,13 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -731,13 +731,13 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Add another 'Images' paragraph with node langcode as 'english'.
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more');
     // Check the paragraph langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[2];
+    $images = $this->getTestFiles('image')[2];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -756,13 +756,13 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[3];
+    $images = $this->getTestFiles('image')[3];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php
similarity index 72%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php
index 200db0fc5e..ef7d4ec74d 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsTypesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -30,7 +30,7 @@ public function testRemoveTypesWithContent() {
 
     // Add a test node with a Paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'test_node'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('paragraphed_test test_node has been created.');
@@ -61,7 +61,7 @@ public function testParagraphTypeIcon() {
     // Add the paragraph type with icon.
     $this->drupalGet('admin/structure/paragraphs_type/add');
     $this->assertText('Paragraph type icon');
-    $test_files = $this->drupalGetTestFiles('image');
+    $test_files = $this->getTestFiles('image');
     $fileSystem = \Drupal::service('file_system');
     $edit = [
       'label' => 'Test paragraph type',
@@ -90,7 +90,7 @@ public function testParagraphTypeIcon() {
 
     // Delete the icon.
     $this->drupalGet('admin/structure/paragraphs_type/test_paragraph_type_icon');
-    $this->drupalPostAjaxForm(NULL, [], 'icon_file_remove_button');
+    $this->drupalPostForm(NULL, [], 'icon_file_remove_button');
     $this->drupalPostForm(NULL, [], t('Save'));
 
     // Check that the icon file usage has been deregistered.
@@ -98,6 +98,46 @@ public function testParagraphTypeIcon() {
     $this->assertEqual($usages, []);
   }
 
+  /**
+   * Tests the paragraph type default icon settings.
+   */
+  public function testParagraphTypeDefaultIcon() {
+    /** @var \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository */
+    $entity_repository = \Drupal::service('entity.repository');
+
+    $admin_user = $this->drupalCreateUser([
+      'administer paragraphs types',
+      'access files overview',
+    ]);
+    $this->drupalLogin($admin_user);
+    // Add the paragraph type with icon.
+    $this->drupalGet('admin/structure/paragraphs_type/add');
+    $this->assertText('Paragraph type icon');
+    $test_files = $this->getTestFiles('image');
+    $fileSystem = \Drupal::service('file_system');
+    $edit = [
+      'label' => 'Test paragraph type',
+      'id' => 'test_paragraph_type_icon',
+      'files[icon_file]' => $fileSystem->realpath($test_files[0]->uri),
+    ];
+    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $this->assertText('Saved the Test paragraph type Paragraphs type.');
+
+    // Check if the icon is created from defaults if not exists.
+    $paragraph_type = ParagraphsType::load('test_paragraph_type_icon');
+    $file = $entity_repository->loadEntityByUuid('file', $paragraph_type->get('icon_uuid'));
+    $file->delete();
+    $this->resetAll();
+    $this->drupalGet('admin/structure/paragraphs_type');
+    // New default icon name.
+    $default_icon_name = 'test_paragraph_type_icon-default-icon.png';
+    $this->assertRaw($default_icon_name);
+    $this->clickLink('Edit');
+    $this->assertText($default_icon_name);
+    $file = $entity_repository->loadEntityByUuid('file', $paragraph_type->get('icon_uuid'));
+    $this->assertTrue($file);
+  }
+
   /**
    * Test the paragraph type description settings.
    */
@@ -123,7 +163,7 @@ public function testParagraphTypeDescription() {
     $this->assertText('Description');
     $this->assertText($description_text);
     $this->assertRaw($description_markup);
-    //Check if description is at Description column
+    // Check if description is at Description column.
     $header_position = count($this->xpath('//table/thead/tr/th[.="Description"]/preceding-sibling::th'));
     $row_position = count($this->xpath('//table/tbody/tr/td[.="' . $description_text . '"]/preceding-sibling::td'));
     $this->assertEqual($header_position, $row_position);
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php
similarity index 94%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php
index 3edcddc57c..b4939e237e 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
 
 /**
@@ -12,8 +11,6 @@
  */
 class ParagraphsUiTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -108,8 +105,8 @@ public function testEmptyRequiredField() {
     // "remove" mode in the required field.
     $title = 'Remove mode';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
+    $this->drupalPostForm(NULL, [], 'field_content_0_remove');
     $this->assertNoText($field_title . ' field is required');
     $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
     $this->assertText($field_title . ' field is required');
diff --git a/web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php
similarity index 78%
rename from web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php
index 6917bdbe9c..aeb7786d38 100644
--- a/web/modules/paragraphs/src/Tests/Classic/ParagraphsWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php
@@ -1,8 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Classic;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Classic;
 
 /**
  * Tests paragraphs widget buttons.
@@ -11,8 +9,6 @@
  */
 class ParagraphsWidgetButtonsTest extends ParagraphsTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Tests the widget buttons of paragraphs.
    */
@@ -27,7 +23,7 @@ public function testWidgetButtons() {
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -35,7 +31,7 @@ public function testWidgetButtons() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
@@ -49,18 +45,18 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $text);
     $closed_mode_text = 'closed_mode_text';
     // Click "Collapse" button on both paragraphs.
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse');
     // Verify that we have warning message for each paragraph.
     $this->assertNoUniqueText('You have unsaved changes on this Paragraph item.');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">' . $closed_mode_text);
+    $this->assertRaw('<span class="summary-content">' . $closed_mode_text);
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertText($closed_mode_text);
@@ -69,12 +65,12 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'preview');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text);
     $preview_mode_text = 'preview_mode_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text];
     // Click "Collapse" button.
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     $this->assertText('You have unsaved changes on this Paragraph item.');
     $this->assertText($preview_mode_text);
     $this->drupalPostForm(NULL, [], t('Save'));
@@ -85,10 +81,10 @@ public function testWidgetButtons() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertText($preview_mode_text);
     // Click "Remove" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $this->assertText('Deleted Paragraph: text_paragraph');
     // Click "Restore" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_restore');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $preview_mode_text);
     $restore_text = 'restore_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $restore_text];
@@ -100,10 +96,10 @@ public function testWidgetButtons() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertText($restore_text);
     // Click "Remove" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $this->assertText('Deleted Paragraph: text_paragraph');
     // Click "Confirm Removal" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_confirm_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertNoText($restore_text);
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php
similarity index 80%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php
index 71ab13c5b3..0d5e062fe2 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php
@@ -1,11 +1,12 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\filter\Entity\FilterFormat;
 use Drupal\image\Entity\ImageStyle;
 use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\user\RoleInterface;
 use Drupal\user\Entity\Role;
 
@@ -116,21 +117,28 @@ public function testParagraphAccessCheck() {
     // Add a new Paragraphs images item.
     $this->drupalPostForm(NULL, NULL, t('Add images'));
 
-    $images = $this->drupalGetTestFiles('image');
+    $images = $this->getTestFiles('image');
 
     // Create a file, upload it.
-    file_unmanaged_copy($images[0]->uri, 'temporary://privateImage.jpg');
+    $file_system = \Drupal::service('file_system');
+    $file_system->copy($images[0]->uri, 'temporary://privateImage.jpg');
     $file_path = $this->container->get('file_system')
       ->realpath('temporary://privateImage.jpg');
 
     // Create a file, upload it.
-    file_unmanaged_copy($images[1]->uri, 'temporary://privateImage2.jpg');
+    $file_system->copy($images[1]->uri, 'temporary://privateImage2.jpg');
     $file_path_2 = $this->container->get('file_system')
       ->realpath('temporary://privateImage2.jpg');
 
     $edit = array(
       'title[0][value]' => 'Security test node',
-      'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => [$file_path, $file_path_2],
+      'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path,
+    );
+
+    $this->drupalPostForm(NULL, $edit, t('Upload'));
+
+    $edit = array(
+      'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2,
     );
 
     $this->drupalPostForm(NULL, $edit, t('Upload'));
@@ -181,7 +189,7 @@ public function testParagraphAccessCheck() {
     // Check the remove button is present.
     $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]'));
     // Delete the Paragraph and save.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_demo_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $node = $this->getNodeByTitle('delete_permissions');
     $this->assertUrl('node/' . $node->id());
@@ -249,4 +257,47 @@ public function testParagraphAccessCheck() {
     $this->assertRaw('paragraph--unpublished');
   }
 
+  /**
+   * Tests the Paragraph validation with filter access.
+   */
+  public function testParagraphsTextFormatValidation() {
+    $filtered_html_format = FilterFormat::create([
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+    ]);
+    $filtered_html_format->save();
+    $permissions = [
+      'create paragraphed_content_demo content',
+      'edit any paragraphed_content_demo content',
+      $filtered_html_format->getPermissionName()
+    ];
+    $this->loginAsAdmin($permissions);
+    // Create a node with a Text Paragraph using the filtered html format.
+    $this->drupalGet('node/add/paragraphed_content_demo');
+    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->assertText('Text');
+    $edit = [
+      'title[0][value]' => 'access_validation_test',
+      'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Test',
+    ];
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->assertText('paragraphed_content_demo access_validation_test has been created.');
+    $this->drupalLogout();
+    // Login as an user without the Text Format permission.
+    $user = $this->drupalCreateUser([
+      'administer nodes',
+      'edit any paragraphed_content_demo content',
+    ]);
+    $this->drupalLogin($user);
+    $node = $this->getNodeByTitle('access_validation_test');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->assertText('paragraphed_content_demo access_validation_test has been updated.');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_collapse');
+    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->assertText('paragraphed_content_demo access_validation_test has been updated.');
+    $this->assertNoText('The value you selected is not a valid choice.');
+  }
+
 }
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php
similarity index 97%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php
index 2fa86f4aca..d524c644bb 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAddModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\paragraphs\Entity\ParagraphsType;
 
 /**
@@ -12,8 +11,6 @@
  */
 class ParagraphsExperimentalAddModesTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Tests that paragraphs field does not allow default values.
    */
@@ -121,10 +118,10 @@ public function testSelectMode() {
    */
   protected function assertAddButtons($options) {
     $this->drupalGet('node/add/paragraphed_test');
-    $buttons = $this->xpath('//input[@class="field-add-more-submit button js-form-submit form-submit"]');
+    $buttons = $this->xpath('//input[@class="field-add-more-submit paragraphs-add-wrapper button js-form-submit form-submit"]');
     // Check if the buttons are in the same order as the given array.
     foreach ($buttons as $key => $button) {
-      $this->assertEqual($button['value'], $options[$key]);
+      $this->assertEqual($button->getValue(), $options[$key]);
     }
     $this->assertTrue(count($buttons) == count($options), 'The amount of drop down options matches with the given array');
   }
@@ -142,7 +139,7 @@ protected function assertSelectOptions($options, $paragraphs_field) {
     $buttons = $this->xpath('//*[@name="' . $paragraphs_field . '[add_more][add_more_select]"]/option');
     // Check if the options are in the same order as the given array.
     foreach ($buttons as $key => $button) {
-      $this->assertEqual($button['value'], $options[$key]);
+      $this->assertEqual($button->getValue(), $options[$key]);
     }
     $this->assertTrue(count($buttons) == count($options), 'The amount of select options matches with the given array');
     $this->assertNotEqual($this->xpath('//*[@name="' . $paragraphs_field .'_add_more"]'), [], 'The add button is displayed');
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php
similarity index 84%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php
index 18bbc64531..8c3189703b 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAdministrationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
@@ -13,7 +12,6 @@
  */
 class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
   use ParagraphsTestBaseTrait;
 
   /**
@@ -68,8 +66,8 @@ public function testParagraphsRevisions() {
 
     // Create node with our paragraphs.
     $this->drupalGet('node/add/paragraphs');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     $edit = [
       'title[0][value]' => 'TEST TITEL',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1',
@@ -146,7 +144,7 @@ public function testParagraphsCreation() {
 
     // Assert suggested 'Add a paragraph type' link when there is no type yet.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->assertText('There are no paragraphs type entities yet.');
+    $this->assertText('There are no Paragraphs types yet.');
     $this->drupalGet('admin/structure/types/manage/paragraphs/fields/add-field');
     $edit = [
       'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
@@ -182,7 +180,7 @@ public function testParagraphsCreation() {
 
     // Change the add more button to select mode.
     $this->clickLink(t('Manage form display'));
-    $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update'));
     $this->drupalPostForm(NULL, [], t('Save'));
 
@@ -211,7 +209,7 @@ public function testParagraphsCreation() {
     $field_name = 'field_paragraphs';
 
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostAjaxForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit");
+    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit");
 
     // Enable setting.
     $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button');
@@ -221,17 +219,17 @@ public function testParagraphsCreation() {
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     $this->assertText('Add mode: Buttons', 'Checking the settings value.');
 
-    $this->drupalPostAjaxForm(NULL, array(), $field_name . "_settings_edit");
+    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
     // Assert the 'Buttons' option is selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button', 'Updated value is correct!.');
 
     // Add two Text + Image paragraphs in article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
 
     // Upload some images.
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
 
     $edit = array(
@@ -262,25 +260,25 @@ public function testParagraphsCreation() {
     // Test for closed setting.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Enable setting.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Check if the setting is stored.
     $this->assertText('Edit mode: Closed', 'Checking the settings value.');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Assert the 'Closed' option is selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Updated value correctly.');
     $this->drupalGet('node/1/edit');
     // The textareas for paragraphs should not be visible.
     $this->assertNoRaw('field_paragraphs[0][subform][field_text][0][value]');
     $this->assertNoRaw('field_paragraphs[1][subform][field_text][0][value]');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 1, ' . $files[0]->filename);
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Test text 2, ' . $files[1]->filename);
+    $this->assertRaw('<span class="summary-content">Test text 1</span>, <span class="summary-content">' . $files[0]->filename);
+    $this->assertRaw('<span class="summary-content">Test text 2</span>, <span class="summary-content">' . $files[1]->filename);
 
     // Test for preview option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     $edit = [
       'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
       'fields[field_paragraphs][settings_edit_form][settings][closed_mode]' => 'preview',
@@ -297,7 +295,7 @@ public function testParagraphsCreation() {
 
     // Test for open option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostAjaxForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
     // Assert the "Closed" and "Preview" options are selected.
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed', 'Correctly updated the "Edit mode" value.');
     $this->assertOptionSelected('edit-fields-field-paragraphs-settings-edit-form-settings-closed-mode', 'preview', 'Correctly updated the "Closed mode" value.');
@@ -320,19 +318,17 @@ public function testParagraphsCreation() {
     $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2');
     $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Remove 2nd paragraph.
-    $this->drupalPostForm(NULL, NULL, t('Remove'));
+    $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
     $this->assertNoField('field_paragraphs[1][subform][field_text][0][value]');
     $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Assert the paragraph is not deleted unless the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     // Remove the second paragraph.
-    $this->drupalPostForm(NULL, [], t('Remove'));
+    $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
     $this->assertNoRaw('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt',
-      'field_paragraphs[0][subform][field_image][0][width]' => 300,
-      'field_paragraphs[0][subform][field_image][0][height]' => 300,
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Assert the paragraph is deleted after the user saves the node.
@@ -378,7 +374,7 @@ public function testParagraphsCreation() {
 
     // Add a new article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_test_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more');
 
     // Ensure that nested header actions do not add a visible weight field.
     $this->assertNoFieldByName('field_paragraphs[0][subform][field_paragraphs][header_actions][_weight]');
@@ -386,7 +382,7 @@ public function testParagraphsCreation() {
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
     // Test the new field is displayed.
     $this->assertFieldByName('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]');
 
@@ -406,7 +402,7 @@ public function testParagraphsCreation() {
     // Test that unsupported widgets are not displayed.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     $select = $this->xpath('//*[@id="edit-fields-field-paragraphs-type"]')[0];
-    $this->assertEqual(count($select->option), 2);
+    $this->assertCount(2, $select->findAll('css', 'option'));
     $this->assertRaw('value="paragraphs" selected="selected"');
 
     // Check that Paragraphs is not displayed as an entity_reference field
@@ -432,12 +428,12 @@ public function testParagraphsCreation() {
     ), array());
     $this->clickLink(t('Manage form display'));
     $this->drupalPostForm(NULL, [], 'Save');
-    $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
+    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
     $edit = array(
       'title[0][value]' => 'Nested twins',
     );
@@ -471,7 +467,7 @@ public function testParagraphsCreation() {
     $node = $this->drupalGetNodeByTitle('Nested twins');
 
     // Create a node with a reference in a Paragraph.
-    $this->drupalPostAjaxForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
+    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
     \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
     $edit = [
       'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')',
@@ -485,21 +481,19 @@ public function testParagraphsCreation() {
 
     // Adding another required paragraph and deleting that again should not
     // validate closed paragraphs but trying to save the node should.
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_node_test_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_node_test_add_more');
     $this->assertNoText('The referenced entity (node: ' . $node->id() . ') does not exist.');
     $this->assertFieldByName('field_paragraphs[1][subform][field_entity_reference][0][target_id]');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_1_remove');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_1_remove');
     $this->assertNoText('The referenced entity (node: ' . $node->id() . ') does not exist.');
     $this->assertNoFieldByName('field_paragraphs[1][subform][field_entity_reference][0][target_id]');
     $this->drupalPostForm(NULL, [], t('Save'));
-    $this->assertText('The referenced entity (node: ' . $node->id() . ') does not exist.');
+    $this->assertText('Validation error on collapsed paragraph field_entity_reference.0.target_id: The referenced entity (node: ' . $node->id() . ') does not exist.');
 
     // Attempt to edit the Paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    // Validate that the reference is removed.
-    $this->assertNoErrorsLogged();
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     // Try to collapse with an invalid reference.
-    $this->drupalPostAjaxForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
     // Paragraph should be still in edit mode.
     $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][0][target_id]');
     $this->assertFieldByName('field_paragraphs[0][subform][field_entity_reference][1][target_id]');
@@ -525,13 +519,13 @@ public function testParagraphsCreation() {
     // Attempt to edit the Paragraph.
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Attempt to edit the Paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     // Try to save with an invalid reference.
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertText('There are no entities matching "foo".');
     // Remove the Paragraph and save the node.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('choke test has been updated.');
 
@@ -550,34 +544,7 @@ public function testParagraphsCreation() {
     $this->drupalGet('admin/content/files');
     $this->clickLink('1 place');
     $label = $this->xpath('//tbody/tr/td[1]');
-    $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->asXML()))), 'test required > field_paragraphs > Paragraphs');
-  }
-
-  /**
-   * Asserts that a select option in the current page is checked.
-   *
-   * @param string $id
-   *   ID of select field to assert.
-   * @param string $option
-   *   Option to assert.
-   * @param string $message
-   *   (optional) A message to display with the assertion. Do not translate
-   *   messages: use format_string() to embed variables in the message text, not
-   *   t(). If left blank, a default message will be displayed.
-   * @param string $group
-   *   (optional) The group this message is in, which is displayed in a column
-   *   in test output. Use 'Debug' to indicate this is debugging output. Do not
-   *   translate this string. Defaults to 'Browser'; most tests do not override
-   *   this default.
-   *
-   * @return bool
-   *   TRUE on pass, FALSE on fail.
-   *
-   * @todo Remove function once core issue is resolved: https://www.drupal.org/node/2530092
-   */
-  protected function assertOptionSelected($id, $option, $message = '', $group = 'Browser') {
-    $elements = $this->xpath('//select[contains(@id, :id)]//option[@value=:option]', array(':id' => $id, ':option' => $option));
-    return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : SafeMarkup::format('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), $group);
+    $this->assertEqual(trim(htmlspecialchars_decode(strip_tags($label[0]->getText()))), 'test required > field_paragraphs > Paragraphs');
   }
 
   /**
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php
similarity index 95%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php
index b39a865d62..ceaa62f3c4 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalAlterByTypeTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests paragraphs experimental alter widget by type.
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php
similarity index 86%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php
index 7a6f4dd9ad..207a5eb581 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalBehaviorsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php
@@ -1,9 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\paragraphs\Entity\Paragraph;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests paragraphs behavior plugins.
@@ -12,8 +9,6 @@
  */
 class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -172,7 +167,7 @@ public function testBehaviorPluginsFields() {
       'behavior_plugins[test_text_color][enabled]' => TRUE,
     ];
     $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
     $edit = [
       'title[0][value]' => 'paragraph with no fields',
       'field_paragraphs[0][subform][field_text_test][0][value]' => 'my behavior plugin does not have any field',
@@ -185,25 +180,14 @@ public function testBehaviorPluginsFields() {
     $this->drupalPostForm('admin/structure/paragraphs_type/fieldless', ['behavior_plugins[test_dummy_behavior][enabled]' => TRUE], t('Save'));
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_fieldless_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_fieldless_add_more');
     $edit = ['title[0][value]' => t('Fieldless')];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
     $this->assertResponse(200);
 
-    $field_definition = \Drupal::service('entity_field.manager')->getFieldDefinitions('paragraph', $paragraph_type)['uid'];
-    $field_definition->getConfig($paragraph_type)->save();
-
-    // Enable the test field selection plugin.
-    $edit = [
-      'behavior_plugins[test_field_selection][enabled]' => TRUE,
-    ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
-    // Assert that the uid field is not shown as an option for the select.
-    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
-    $this->assertNoOption('edit-behavior-plugins-test-field-selection-settings-field-selection', 'uid');
     // Add a paragraphed content.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
     $edit = [
       'title[0][value]' => 'field_override_test',
       'field_paragraphs[0][subform][field_text_test][0][value]' => 'This is a test',
@@ -211,8 +195,8 @@ public function testBehaviorPluginsFields() {
     $this->drupalPostForm(NULL, $edit, 'Save');
     // Check that the summary does not have the user displayed.
     $node = $this->getNodeByTitle('field_override_test');
-    $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse');
-    $this->assertRaw('paragraphs-collapsed-description">This is a test');
+    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse');
+    $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a test');
   }
 
   /**
@@ -249,8 +233,8 @@ public function testCollapsedSummary() {
     $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
 
     // Add a node and enabled plugins.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more');
 
     $this->assertField('field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]');
     $this->assertField('field_paragraphs[1][behavior_plugins][test_bold_text][bold_text]');
@@ -272,11 +256,11 @@ public function testCollapsedSummary() {
     $this->assertFieldByXPath('//*[@id="edit-field-paragraphs-1-top-icons"]/span[@class="paragraphs-icon paragraphs-icon-bold"]');
 
     // Assert that the summary includes the text of the behavior plugins.
-    $this->assertRaw('class="paragraphs-collapsed-description">first_paragraph, Bold: Yes, Text color: blue');
-    $this->assertRaw('class="paragraphs-collapsed-description">nested_paragraph, Bold: No, Text color: blue, Bold: Yes');
+    $this->assertRaw('first_paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Bold</span>Yes</span><span class="summary-plugin"><span class="summary-plugin-label">Text color</span>blue</span>');
+    $this->assertRaw('nested_paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Bold</span>Yes</span></div></div>');
 
     // Add an empty nested paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'collapsed_test',
     ];
@@ -284,7 +268,7 @@ public function testCollapsedSummary() {
 
     // Check an empty nested paragraph summary.
     $this->clickLink('Edit');
-    $this->assertRaw('class="paragraphs-collapsed-description">');
+    $this->assertRaw('class="paragraphs-description paragraphs-collapsed-description">');
 
   }
 
@@ -324,9 +308,9 @@ public function testBehaviorSubform() {
     $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
 
     // Add a node and enabled plugins.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'collapsed_test',
       'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => 'nested text paragraph',
@@ -344,7 +328,6 @@ public function testBehaviorSubform() {
       'field_paragraphs[1][_weight]' => 0,
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertNoErrorsLogged();
     $this->clickLink('Edit');
     $this->assertFieldByName('field_paragraphs[0][behavior_plugins][test_text_color][text_color]', 'red');
 
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php
similarity index 98%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php
index 728136208d..252b63923c 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalConfigTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\NodeType;
@@ -52,7 +52,7 @@ public function testFieldTranslationDisabled() {
     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
 
     // Create a node with a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'paragraphed_title'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php
similarity index 87%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php
index 4bf2e28894..9b84214317 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalContactTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\contact\Entity\ContactForm;
 
@@ -39,10 +39,10 @@ public function testContactForm() {
     $this->addParagraphsField($contact_form->id(), 'paragraphs', 'contact_message');
     // Add a paragraph to the contact form.
     $this->drupalGet('contact/test_contact_form');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
     // Check that the paragraph is displayed.
     $this->assertText('paragraphs_contact');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'paragraphs_0_remove');
     $elements = $this->xpath('//table[starts-with(@id, :id)]/tbody', [':id' => 'paragraphs-values']);
     $header = $this->xpath('//table[starts-with(@id, :id)]/thead', [':id' => 'paragraphs-values']);
     $this->assertEqual($elements, []);
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php
similarity index 98%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php
index 113b5b1c50..d734de56f9 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalContentModerationTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php
@@ -1,13 +1,8 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -15,12 +10,8 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalContentModerationTranslationsTest extends BrowserTestBase {
+class ParagraphsExperimentalContentModerationTranslationsTest extends ParagraphsExperimentalTestBase {
 
-  use LoginAdminTrait;
-  use FieldUiTestTrait;
-  use ParagraphsTestBaseTrait;
-  use ParagraphsCoreVersionUiTestTrait;
   use ParagraphsLastEntityQueryTrait;
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php
similarity index 98%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php
index 8cd041303d..c99d382fc9 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalDragAndDropModeTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php
@@ -1,21 +1,17 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\node\Entity\Node;
 use Drupal\paragraphs\Entity\Paragraph;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
 /**
  * Tests the drag and drop mode of paragraphs.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalDragAndDropModeTest extends BrowserTestBase {
-
-  use ParagraphsTestBaseTrait;
+class ParagraphsExperimentalDragAndDropModeTest extends ParagraphsExperimentalTestBase {
 
   /**
    * Modules to be enabled.
@@ -44,7 +40,6 @@ public function setUp() {
       'region' => 'content',
       'settings' => [
         'edit_mode' => 'closed',
-        'add_mode' => 'modal',
         'form_display_mode' => 'default',
       ],
     ];
@@ -879,4 +874,23 @@ public function testChangeParagraphMoveAllFromNestedContainer() {
     $this->assertEquals($container->id(), $text_paragraph_2->get('parent_id')->value);
   }
 
+  /**
+   * Tests enabling and saving drag and drop with an empty node title.
+   */
+  public function testEmptyNodeTitle() {
+
+    // Create node.
+    $this->drupalGet('/node/add/paragraphed_test');
+    $this->getSession()->getPage()->pressButton('Add text');
+
+    // Enable drag and drop.
+    $this->drupalPostForm(NULL, [], 'Drag & drop');
+
+    // Complete drag and drop.
+    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
+    $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_text][0][value]');
+    $this->assertSession()->pageTextNotContains('Title field is required.');
+
+  }
+
 }
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
similarity index 88%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
index cd18ca97a9..ef93e2fc67 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests paragraphs duplicate feature.
@@ -31,8 +31,8 @@ public function testDuplicateButton() {
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text_01 = 'recognizable_text_01';
@@ -50,7 +50,7 @@ public function testDuplicateButton() {
 
     // Click "Duplicate" button on A and move C to the first position.
     $edit = ['field_paragraphs[2][_weight]' => -1];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_duplicate');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_duplicate');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', 'A');
     $this->assertFieldByName('field_paragraphs[0][_weight]', 1);
     $this->assertFieldByName('field_paragraphs[1][subform][field_text][0][value]', 'B');
@@ -77,8 +77,8 @@ public function testDuplicateButton() {
     $this->assertFieldByName('field_paragraphs[3][subform][field_text][0][value]', 'B');
 
     // Delete the second A, then duplicate C.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_remove');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_2_duplicate');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_2_duplicate');
     $this->drupalPostForm(NULL, [], t('Save'));
 
     $this->drupalGet('node/' . $node->id() . '/edit');
@@ -92,7 +92,7 @@ public function testDuplicateButton() {
     // Disable show duplicate action.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $this->assertText('Features: Duplicate, Collapse / Edit all');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => FALSE], t('Update'));
     $this->assertText('Features: Collapse / Edit all');
     $this->drupalPostForm(NULL, [], 'Save');
@@ -104,7 +104,7 @@ public function testDuplicateButton() {
     // Enable show duplicate action.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $this->assertText('Features: Collapse / Edit all');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => TRUE], t('Update'));
     $this->assertText('Features: Duplicate, Collapse / Edit all');
     $this->drupalPostForm(NULL, [], 'Save');
@@ -136,7 +136,7 @@ public function testDuplicateButtonWithNesting() {
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ], []);
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $edit = [
@@ -147,7 +147,7 @@ public function testDuplicateButtonWithNesting() {
 
     // Add a text field to nested paragraph.
     $text = 'recognizable_text';
-    $this->drupalPostAjaxForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => $text,
     ];
@@ -158,8 +158,8 @@ public function testDuplicateButtonWithNesting() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Click "Duplicate" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_duplicate');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_duplicate');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $this->assertFieldByName('field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]', $text);
     $this->assertFieldByName('field_paragraphs[1][subform][field_nested][0][subform][field_text][0][value]', $text);
 
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php
similarity index 62%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php
index c6a5d31523..590d27dc6b 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEditModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php
@@ -1,8 +1,8 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+use Drupal\block_content\Entity\BlockContent;
 
 /**
  * Tests paragraphs edit modes.
@@ -11,8 +11,6 @@
  */
 class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -21,6 +19,7 @@ class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase
   public static $modules = [
     'image',
     'block_field',
+    'block_content',
     'link',
     'field_ui'
   ];
@@ -49,14 +48,14 @@ public function testCollapsedSummary() {
 
     // Set edit mode to closed.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostAjaxForm(NULL, [], "field_paragraphs_settings_edit");
+    $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit");
     $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Add a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
 
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
 
     // Create a node with an image and text.
@@ -76,29 +75,27 @@ public function testCollapsedSummary() {
 
     // Assert the summary is correctly generated.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">' . $files[0]->filename . ', text_summary');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">' . $this->admin_user->label());
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Title example');
+    $this->assertRaw('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>');
+    $this->assertRaw('<span class="summary-content">' . $this->admin_user->label());
+    $this->assertRaw('<span class="summary-content">Title example');
 
     // Edit and remove alternative text.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary',
-      'field_paragraphs[0][subform][field_image][0][width]' => 300,
-      'field_paragraphs[0][subform][field_image][0][height]' => 300,
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     // Assert the summary is correctly generated.
-    $this->assertRaw('<div class="paragraphs-collapsed-description">alternative_text_summary, text_summary');
+    $this->assertRaw('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>');
 
     // Remove image.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
     $this->drupalPostForm(NULL, [], t('Save'));
 
     // Assert the summary is correctly generated.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">text_summary');
+    $this->assertRaw('<span class="summary-content">text_summary');
 
     $this->addParagraphsType('nested_paragraph');
     static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_paragraph', 'nested_content', 'Nested Content', 'entity_reference_revisions', ['settings[target_type]' => 'paragraph'], []);
@@ -109,7 +106,7 @@ public function testCollapsedSummary() {
 
     $this->drupalGet('node/add/paragraphed_test');
     $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
-    $this->drupalPostAjaxForm(NULL, NULL, t('field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more'));
+    $this->drupalPostForm(NULL, NULL, t('field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more'));
     $edit = [
       'title[0][value]' => 'Node title',
       'field_paragraphs[0][subform][field_nested_content][0][subform][field_user][0][target_id]' => $test_user->label() . ' (' . $test_user->id() . ')',
@@ -121,8 +118,8 @@ public function testCollapsedSummary() {
 
     $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['title' => 'Node title']);
     $this->drupalGet('node/' . current($nodes)->id() . '/edit');
-    $this->drupalPostAjaxForm(NULL, [], t('field_paragraphs_0_edit'));
-    $this->drupalPostAjaxForm(NULL, [], t('field_paragraphs_0_collapse'));
+    $this->drupalPostForm(NULL, [], t('field_paragraphs_0_edit'));
+    $this->drupalPostForm(NULL, [], t('field_paragraphs_0_collapse'));
     $this->assertResponse(200);
 
     // Add a Block Paragraphs type.
@@ -130,20 +127,36 @@ public function testCollapsedSummary() {
     $this->addFieldtoParagraphType('block_paragraph', 'field_block', 'block_field');
 
     // Test the summary of a Block field.
+    $after_block2 = BlockContent::create([
+      'info' => 'Llama custom block',
+      'type' => 'basic_block',
+    ]);
+    $after_block2->save();
+
+    $this->placeBlock($after_block2->id());
+
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
     $edit = [
-      'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'system_breadcrumb_block',
+      'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'block_content:' . $after_block2->uuid(),
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Breadcrumbs');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->assertRaw('<span class="summary-content">Llama custom block');
+    $edit = ['title[0][value]' => 'Test llama block'];
+    $this->drupalPostForm(NULL, $edit, t('Save'));
+    // Delete the block.
+    $after_block2->delete();
+    // Attempt to edit the node when the node is deleted.
+    $node = $this->getNodeByTitle('Test llama block');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertResponse(200);
 
     // Test the summary of a Block field.
     $paragraph_type = 'link_paragraph';
     $this->addParagraphsType($paragraph_type);
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'link', 'Link', 'link', [], []);
     // Create a node with a link paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_link_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_link_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'Test link',
       'field_paragraphs[0][subform][field_link][0][uri]' => 'http://www.google.com',
@@ -151,16 +164,16 @@ public function testCollapsedSummary() {
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Check the summary when no link title is provided.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">http://www.google.com');
+    $this->assertRaw('<span class="summary-content">http://www.google.com');
     // Set a link title.
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_link][0][title]' => 'Link title',
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Check the summary when the link title is set.
     $this->clickLink(t('Edit'));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">Link title');
+    $this->assertRaw('<span class="summary-content">Link title');
 
     // Allow the user to select if the paragraphs is published or not.
     $edit = [
@@ -176,7 +189,7 @@ public function testCollapsedSummary() {
     $this->drupalPostForm('admin/structure/paragraphs_type/nested_paragraph/form-display', $edit, 'Save');
 
     // Add a unpublished text paragraph and check its summary when unpublished.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_title_add_more');
     $edit = [
       'title[0][value]' => 'Access summary test',
       'field_paragraphs[0][subform][field_title][0][value]' => 'memorable_summary_title',
@@ -186,10 +199,11 @@ public function testCollapsedSummary() {
     $this->assertNoText('memorable_summary_title');
     $node = $this->getNodeByTitle('Access summary test');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_summary_title');
+    $this->assertRaw('<span class="summary-content">memorable_summary_title');
+    $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
 
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more');
 
     // Add a nested paragraph and with the parent unpublished, check the
     // summary.
@@ -203,10 +217,25 @@ public function testCollapsedSummary() {
     $this->assertNoText('memorable_nested_summary_title');
     $node = $this->getNodeByTitle('Access nested summary test');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_nested_summary_title');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">memorable_nested_summary_title');
+    $this->assertRaw('<span class="summary-content">memorable_nested_summary_title');
+    $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
+    $this->assertRaw('<span class="summary-content">memorable_nested_summary_title');
+    $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
+
+    // Assert the unpublished icon.
+    $permissions = [
+      'edit any paragraphed_test content',
+    ];
+    $this->loginAsAdmin($permissions);
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertRaw('<span class="summary-content">memorable_nested_summary_title');
+    $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
+    $this->assertRaw('<span class="summary-content">memorable_nested_summary_title');
+    $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
   }
 
 }
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
similarity index 98%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
index 247ebf9e8d..7465b193b8 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests the translation of heavily nested / specialized setup.
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php
similarity index 90%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php
index 111f5782f8..26c9131019 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalFieldGroupTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests the field group on node.
@@ -49,13 +49,14 @@ public function testFieldGroup() {
 
     // Put the text field into the field group.
     $edit = [
+      'fields[group_field][region]' => 'content',
       'fields[field_text][parent]' => 'group_field'
     ];
     $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save'));
 
     // Create a node with a paragraph.
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostAjaxForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
 
     // Test if the new field group is displayed.
     $this->assertText('field_group');
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php
similarity index 87%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php
index cce11d7286..9e6d0b7444 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalHeaderActionsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Symfony\Component\CssSelector\CssSelectorConverter;
@@ -62,7 +62,7 @@ public function testHeaderActions() {
     $this->assertEqual(1, count($table_rows));
 
     // Add second paragraph and check for Collapse/Edit all button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
     $this->assertRaw('field_paragraphs_collapse_all');
     $this->assertRaw('field_paragraphs_edit_all');
 
@@ -77,7 +77,7 @@ public function testHeaderActions() {
     $this->assertRaw('field_paragraphs_1_edit');
 
     // Test Edit all button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
     $this->assertRaw('field_paragraphs_0_collapse');
     $this->assertRaw('field_paragraphs_1_collapse');
 
@@ -93,22 +93,22 @@ public function testHeaderActions() {
     $this->assertNoText('No Paragraph added yet.');
 
     // Add and remove another paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
     $edit = [
       'field_paragraphs[2][subform][field_text][0][value]' => 'Third text',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_2_remove');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_2_remove');
 
     // Check that pressing "Collapse all" does not restore the removed
     // paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
     $this->assertText('First text');
     $this->assertText('Second text');
     $this->assertNoText('Third text');
 
     // Check that pressing "Edit all" does not restore the removed paragraph,
     // either.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_collapse_all');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all');
     $this->assertText('First text');
     $this->assertText('Second text');
     $this->assertNoText('Third text');
@@ -120,12 +120,12 @@ public function testHeaderActions() {
     // and that it is not shown when the paragraph is deleted.
     $this->drupalGet('node/add/paragraphed_test');
     $this->assertRaw('name="field_paragraphs_dragdrop_mode"');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $this->assertNoRaw('name="field_paragraphs_dragdrop_mode"');
 
     // Disable show multiple actions.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => FALSE], t('Update'));
     $this->drupalPostForm(NULL, [], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
@@ -136,7 +136,7 @@ public function testHeaderActions() {
 
     // Enable show "Collapse / Edit all" actions.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_settings_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
     $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => TRUE], t('Update'));
     $this->drupalPostForm(NULL, [], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
@@ -191,13 +191,13 @@ public function testHeaderActionsWithNesting() {
 
     // Checks that Collapse/Edit all button is presented.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more');
     $this->assertRaw('field_paragraphs_collapse_all');
     $this->assertRaw('field_paragraphs_edit_all');
 
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $this->assertNoRaw('field_paragraphs_0_collapse_all');
     $this->assertNoRaw('field_paragraphs_0_edit_all');
     $edit = [
@@ -207,7 +207,7 @@ public function testHeaderActionsWithNesting() {
     $this->drupalPostForm(NULL, $edit, 'Collapse all');
     $this->assertRaw('field-paragraphs-0-edit');
     $this->assertFieldByXPath((new CssSelectorConverter())->toXPath('[name="field_paragraphs_1_edit"] + .paragraphs-dropdown'));
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
     $this->assertRaw('field-paragraphs-0-collapse');
 
     $edit = [
@@ -221,12 +221,12 @@ public function testHeaderActionsWithNesting() {
     $this->clickLink('Edit');
     $this->assertNoText('No Paragraph added yet.');
 
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_nested][1][subform][field_text][0][value]' => 'Second nested text',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $this->assertRaw('field_paragraphs_0_subform_field_nested_collapse_all');
     $this->assertRaw('field_paragraphs_0_subform_field_nested_edit_all');
   }
@@ -271,8 +271,8 @@ public function testHeaderActionsWithMultiFields() {
     );
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_second_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_second_text_paragraph_add_more');
 
     // Checks that we have Collapse\Edit all for each field.
     $this->assertRaw('field_paragraphs_collapse_all');
@@ -283,17 +283,17 @@ public function testHeaderActionsWithMultiFields() {
     $edit = [
       'field_second[0][subform][field_text][0][value]' => 'Second field',
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_second_collapse_all');
+    $this->drupalPostForm(NULL, $edit, 'field_second_collapse_all');
 
     // Checks that we collapsed only children from second field.
     $this->assertNoRaw('field_paragraphs_0_edit');
     $this->assertRaw('field_second_0_edit');
 
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_collapse_all');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all');
     $this->assertRaw('field_paragraphs_0_edit');
     $this->assertRaw('field_second_0_edit');
 
-    $this->drupalPostAjaxForm(NULL, [], 'field_second_edit_all');
+    $this->drupalPostForm(NULL, [], 'field_second_edit_all');
     $this->assertRaw('field_second_0_collapse');
 
     $edit = [
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
similarity index 92%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
index 1ddd6189bb..236253ea95 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
@@ -61,7 +61,7 @@ public function testParagraphsIEFPreview() {
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -75,7 +75,7 @@ public function testParagraphsIEFPreview() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Try to open the previewed paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
   }
 
   /**
@@ -90,7 +90,6 @@ public function testParagraphsIEFChangeOrder() {
     $this->addParagraphsType('simple');
     $this->addParagraphsType('text');
 
-
     // Create a reference to an article.
     $this->fieldUIAddNewField('admin/structure/paragraphs_type/simple', 'article', 'Article', 'field_ui:entity_reference:node', [
       'settings[target_type]' => 'node',
@@ -121,7 +120,7 @@ public function testParagraphsIEFChangeOrder() {
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -136,7 +135,7 @@ public function testParagraphsIEFChangeOrder() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Create second paragraph.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
 
     // Set the values of second paragraph.
     $edit = [
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php
similarity index 86%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php
index 8824207350..4e80a4a51c 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalPreviewTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php
@@ -1,9 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
-
-use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests the configuration of paragraphs.
@@ -12,8 +9,6 @@
  */
 class ParagraphsExperimentalPreviewTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -49,7 +44,7 @@ public function testParagraphsPreview() {
     $test_text_2 = 'dummy_preview_text_2';
     // Create node with two paragraphs.
     $this->drupalGet('node/add/article');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     // Set the value of the paragraphs.
     $edit = [
       'title[0][value]' => 'Page_title',
@@ -68,12 +63,12 @@ public function testParagraphsPreview() {
     $this->clickLink('Back to content editing');
 
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
-    $this->assertEqual($paragraph_1['value'], $test_text_1);
+    $this->assertEqual($paragraph_1->getValue(), $test_text_1);
 
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
     $this->clickLink('Edit');
-    $this->drupalPostAjaxForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
     $edit = [
       'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2,
     ];
@@ -102,8 +97,8 @@ public function testParagraphsPreview() {
     $this->clickLink('Back to content editing');
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
     $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0];
-    $this->assertEqual($paragraph_1['value'], $test_text_1);
-    $this->assertEqual($paragraph_2['value'], $new_test_text_2);
+    $this->assertEqual($paragraph_1->getValue(), $test_text_1);
+    $this->assertEqual($paragraph_2->getValue(), $new_test_text_2);
     $this->drupalPostForm(NULL, [], t('Save'));
 
     $this->assertRaw($test_text_1);
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
similarity index 79%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
index b81d73330f..775b3cc47a 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalReplicateEnableTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Enables replicate module.
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
similarity index 88%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
index 87a0e2963e..c02b7c805d 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
@@ -1,8 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
-
-use Drupal\field_ui\Tests\FieldUiTestTrait;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests the paragraphs summary formatter.
@@ -11,8 +9,6 @@
  */
 class ParagraphsExperimentalSummaryFormatterTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * Modules to enable.
    *
@@ -47,8 +43,8 @@ public function testParagraphsSummaryFormatter() {
     $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary'];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     // Add a paragraph.
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
 
     // Create a node with a text.
     $edit = [
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php
new file mode 100644
index 0000000000..389d461b72
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
+
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Tests\paragraphs\Functional\Classic\ParagraphsTestBase;
+use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+
+/**
+ * Base class for tests.
+ */
+abstract class ParagraphsExperimentalTestBase extends ParagraphsTestBase {
+
+  use ParagraphsTestBaseTrait;
+
+  /**
+   * Sets the Paragraphs widget add mode.
+   *
+   * @param string $content_type
+   *   Content type name where to set the widget mode.
+   * @param string $paragraphs_field
+   *   Paragraphs field to change the mode.
+   * @param string $mode
+   *   Mode to be set. ('dropdown', 'select' or 'button').
+   */
+  protected function setAddMode($content_type, $paragraphs_field, $mode) {
+    $form_display = EntityFormDisplay::load('node.' . $content_type . '.default')
+      ->setComponent($paragraphs_field, [
+        'type' => 'paragraphs',
+        'settings' => ['add_mode' => $mode]
+      ]);
+    $form_display->save();
+  }
+
+  /**
+   * Removes the default paragraph type.
+   *
+   * @param $content_type
+   *   Content type name that contains the paragraphs field.
+   */
+  protected function removeDefaultParagraphType($content_type) {
+    $this->drupalGet('node/add/' . $content_type);
+    $this->drupalPostForm(NULL, [], 'Remove');
+    $this->assertNoText('No paragraphs added yet.');
+  }
+
+}
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php
similarity index 95%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php
index 6689979231..5b0bbd6cc8 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTranslationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -134,8 +134,8 @@ public function testParagraphTranslation() {
     $this->assertText(t('Example published and unpublished'));
     $this->clickLink(t('Edit'));
 
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'field_paragraphs_demo[0][subform][status][value]' => FALSE,
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text'
@@ -260,7 +260,7 @@ public function testParagraphTranslation() {
     $this->drupalPostForm(NULL, $edit, t('Save settings'));
 
     // Create a node with an image paragraph, its alt and title text.
-    $files = $this->drupalGetTestFiles('image');
+    $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
     $file_path = $file_system->realpath($file_system->realpath($files[0]->uri));
     $this->drupalGet('node/add/paragraphed_content_demo');
@@ -422,7 +422,7 @@ public function testParagraphTranslation() {
     $this->drupalGet('node/add/paragraphed_content_demo');
     $this->drupalPostForm(NULL, NULL, t('Add text'));
     $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'title[0][value]' => 'EN llama',
       'langcode[0][value]' => 'en',
@@ -434,7 +434,7 @@ public function testParagraphTranslation() {
     // Create a german translation.
     $node = $this->drupalGetNodeByTitle('EN llama');
     $this->drupalGet('node/' . $node->id() . '/translations/add/en/de');
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_edit_all');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_edit_all');
     $edit = [
       'title[0][value]' => 'DE llama',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'DE text llama',
@@ -444,8 +444,8 @@ public function testParagraphTranslation() {
     // Assert that the summary is displayed in the current language.
     $this->drupalGet('de/node/' . $node->id() . '/edit');
     $this->assertFieldByName('title[0][value]', 'DE llama');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">DE text llama');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">DE nested text llama');
+    $this->assertRaw('<span class="summary-content">DE text llama</span></div></div>');
+    $this->assertRaw('<span class="summary-content">DE nested text llama</span></div></div>');
 
     // Case 2: Referenced entities.
     $this->addParagraphsType('node_reference');
@@ -473,7 +473,7 @@ public function testParagraphTranslation() {
     $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
     // Edit the node again and check the paragraph summary.
     $this->drupalGet('de/node/' . $referencing_node->id() . '/edit');
-    $this->assertRaw('<div class="paragraphs-collapsed-description">DE llama');
+    $this->assertRaw('<span class="summary-content">DE llama</span></div></div>');
   }
 
   /**
@@ -504,7 +504,7 @@ public function testParagraphTranslationMultilingual() {
     $this->drupalPostForm(NULL, NULL, t('Add images'));
     $this->assertParagraphsButtons(1);
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
@@ -536,7 +536,7 @@ public function testParagraphTranslationMultilingual() {
 
     // Edit the french translation and upload a new image.
     $this->clickLink('Edit');
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ], t('Upload'));
@@ -568,12 +568,12 @@ public function testParagraphTranslationMultilingual() {
     $this->assertParagraphsButtons(2);
     // Add an 'Images' paragraph inside the nested one, check the paragraphs
     // langcode are still 'en' and the paragraphs buttons are still displayed.
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Upload a new image, check the paragraphs langcode are still 'en' and the
     // paragraphs buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[2];
+    $images = $this->getTestFiles('image')[2];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -617,7 +617,7 @@ public function testParagraphTranslationMultilingual() {
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
     // Upload another image.
-    $images = $this->drupalGetTestFiles('image')[3];
+    $images = $this->getTestFiles('image')[3];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ], t('Upload'));
@@ -646,12 +646,12 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id(), 'de');
-    $this->assertParagraphsButtons(3);
+      $this->assertParagraphsButtons(3);
     // Upload a new image, check the paragraphs langcode are still 'de' and the
     // paragraphs buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[4];
+    $images = $this->getTestFiles('image')[4];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -698,9 +698,9 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -716,7 +716,7 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'english' and upload another image.
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $edit = [
       'title[0][value]' => 'Title in german (en)',
       'langcode[0][value]' => 'en',
@@ -746,9 +746,9 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostAjaxForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
-    $images = $this->drupalGetTestFiles('image')[0];
+    $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
@@ -770,13 +770,13 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[1];
+    $images = $this->getTestFiles('image')[1];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -810,13 +810,13 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Add another 'Images' paragraph with node langcode as 'english'.
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more');
     // Check the paragraph langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[2];
+    $images = $this->getTestFiles('image')[2];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
@@ -835,13 +835,13 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add images'));
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
-    $images = $this->drupalGetTestFiles('image')[3];
+    $images = $this->getTestFiles('image')[3];
     $this->drupalPostForm(NULL, [
       'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri,
     ], t('Upload'));
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php
similarity index 77%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php
index 8257a1a79e..13a6774296 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php
@@ -1,13 +1,8 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -15,12 +10,8 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalTranslationsTest extends BrowserTestBase {
+class ParagraphsExperimentalTranslationsTest extends ParagraphsExperimentalTestBase {
 
-  use LoginAdminTrait;
-  use FieldUiTestTrait;
-  use ParagraphsTestBaseTrait;
-  use ParagraphsCoreVersionUiTestTrait;
   use ParagraphsLastEntityQueryTrait;
 
   /**
@@ -151,13 +142,13 @@ public function testUntranslatableAutoCollapse() {
     $assert_session->fieldNotExists('field_paragraphs[2][subform][field_text_untranslatable_hide][0][value]');
     $assert_session->buttonNotExists('field_paragraphs_2_collapse');
     $assert_session->buttonNotExists('field_paragraphs_2_edit');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN');
 
     $assert_session->buttonExists('field_paragraphs_1_collapse');
     $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]');
     $page->pressButton('field_paragraphs_1_collapse');
     $assert_session->fieldNotExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN');
     $assert_session->buttonExists('field_paragraphs_1_edit');
 
     $assert_session->buttonExists('field_paragraphs_3_collapse');
@@ -178,17 +169,17 @@ public function testUntranslatableAutoCollapse() {
     $this->drupalGet("/de/node/{$host_node_id}/translations/add/en/de");
     $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]');
     $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN');
     $assert_session->fieldExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]');
     // Translate the content of the translatable fields.
     $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me DE');
     $page->fillField('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]', 'Nested translate me DE');
     // Close all Paragraphs with the new values.
     $page->pressButton('field_paragraphs_collapse_all');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Translate me DE');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Translate me DE');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE');
     // Edit the first Paragraph and update its value.
     $page->pressButton('field_paragraphs_0_edit');
     $page->fillField('field_paragraphs[0][subform][field_text_translatable][0][value]', 'Translate me UPDATE DE');
@@ -200,16 +191,16 @@ public function testUntranslatableAutoCollapse() {
 
     // Edit the translation, assert that the Paragraphs are closed by default.
     $this->drupalGet('de/node/' . $host_node_id . '/edit');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Translate me UPDATE DE');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me EN');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Translate me UPDATE DE');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE');
     // Open all paragraphs.
     $page->pressButton('field_paragraphs_edit_all');
     $assert_session->fieldExists('field_paragraphs[0][subform][field_text_translatable][0][value]');
     $assert_session->fieldExists('field_paragraphs[1][subform][field_text_untranslatable][0][value]');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Do not translate me CLOSED EN');
-    $assert_session->responseContains('<div class="paragraphs-collapsed-description">Nested translate me DE');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Do not translate me CLOSED EN');
+    $assert_session->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Nested translate me DE');
     $assert_session->fieldNotExists('field_paragraphs[3][subform][field_paragraphs][0][subform][field_text_translatable][0][value]');
     // When editing a nested container, all children should follow the widget
     // settings when editing the translation.
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php
similarity index 92%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php
index 6695ff848c..1a66f4f828 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalTypesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
 /**
  * Tests paragraphs types.
@@ -28,7 +28,7 @@ public function testRemoveTypesWithContent() {
 
     // Add a test node with a Paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'test_node'];
     $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']);
     $this->assertEqual(1, count($table_rows));
@@ -53,8 +53,8 @@ public function testRemoveTypesWithContent() {
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Add two different Paragraphs to the node.
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'paragraphs_text_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
     $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']);
     $this->assertEqual(2, count($table_rows));
     $this->drupalPostForm(NULL, [], t('Save'));
@@ -89,7 +89,6 @@ public function testCreateParagraphType() {
       'id' => 'test_name_with_more_than_32_characters'
     ];
     $this->drupalPostForm(NULL, $edit, 'Save and manage fields');
-    $this->assertNoErrorsLogged();
     $this->assertText('Machine-readable name cannot be longer than 32 characters but is currently 38 characters long.');
     $edit['id'] = 'new_test_id';
     $this->drupalPostForm(NULL, $edit, 'Save and manage fields');
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php
similarity index 90%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php
index 536550fc9e..1b32d292eb 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
 
 /**
@@ -12,8 +11,6 @@
  */
 class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
-
   /**
    * {@inheritdoc}
    */
@@ -105,8 +102,8 @@ public function testEmptyRequiredField() {
     // "remove" mode in the required field.
     $title = 'Remove all items';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
+    $this->drupalPostForm(NULL, [], 'field_content_0_remove');
     $this->assertNoText($field_title . ' field is required');
     $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
     $this->assertText($field_title . ' field is required');
@@ -115,9 +112,9 @@ public function testEmptyRequiredField() {
     // removed paragraph.
     $title = 'Valid Removal';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_content_1_remove');
+    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
+    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
+    $this->drupalPostForm(NULL, [], 'field_content_1_remove');
     $this->assertNoText($field_title . ' field is required');
     $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
     $this->assertNoText($field_title . ' field is required');
diff --git a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
similarity index 89%
rename from web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
rename to web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
index 45ec337e60..ef7df522bb 100644
--- a/web/modules/paragraphs/src/Tests/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
@@ -1,8 +1,7 @@
 <?php
 
-namespace Drupal\paragraphs\Tests\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\Experimental;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\field\Entity\FieldConfig;
@@ -16,7 +15,6 @@
  */
 class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase {
 
-  use FieldUiTestTrait;
   use ParagraphsTestBaseTrait;
 
   /**
@@ -48,7 +46,7 @@ public function testWidgetButtons() {
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
     $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save'));
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -56,7 +54,7 @@ public function testWidgetButtons() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
@@ -70,18 +68,18 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_1_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $text);
     $closed_mode_text = 'closed_mode_text';
     // Click "Collapse" button on both paragraphs.
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_1_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse');
     // Verify that we have warning message for each paragraph.
     $this->assertEqual(2, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]")));
-    $this->assertRaw('<div class="paragraphs-collapsed-description">' . $closed_mode_text);
+    $this->assertRaw('<span class="summary-content">' . $closed_mode_text);
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertText($closed_mode_text);
@@ -90,12 +88,12 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetSettings('paragraphed_test', 'field_paragraphs', ['closed_mode' => 'preview']);
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
     $this->assertFieldByName('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text);
     $preview_mode_text = 'preview_mode_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text];
     // Click "Collapse" button.
-    $this->drupalPostAjaxForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
     $this->assertText('You have unsaved changes on this Paragraph item.');
     $this->assertEqual(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]")));
     $this->assertText($preview_mode_text);
@@ -106,7 +104,7 @@ public function testWidgetButtons() {
     // Test the remove function.
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Remove" button.
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
     $this->drupalPostForm(NULL, [], t('Save'));
     $this->assertText('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertNoText($preview_mode_text);
@@ -137,7 +135,7 @@ public function testButtonsVisibility() {
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
     $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save'));
-    $this->drupalPostAjaxForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -145,7 +143,7 @@ public function testButtonsVisibility() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
@@ -181,8 +179,8 @@ public function testButtonsVisibility() {
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostAjaxForm(NULL, [], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalPostForm(NULL, [], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more');
     // Collapse is present on each nesting level.
     $this->assertFieldByName('field_paragraphs_2_collapse');
     $this->assertFieldByName('field_paragraphs_2_subform_field_nested_0_collapse');
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php
index 1c3b43b010..1a769a6b69 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php
@@ -2,19 +2,14 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
 
 /**
  * Tests support for Paragraphs behavior plugins.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalBehaviorsTest extends BrowserTestBase {
-
-  use ParagraphsCoreVersionUiTestTrait;
-  use ParagraphsTestBaseTrait;
+class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase {
 
   /**
    * Modules to enable.
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php
index 9310fdd2b4..45f0ba9d86 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php
@@ -2,19 +2,14 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
 
 /**
  * Tests the Paragraphs user interface.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalUiTest extends BrowserTestBase {
-
-  use LoginAdminTrait;
-  use ParagraphsTestBaseTrait;
+class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
 
   /**
    * Modules to enable.
@@ -46,6 +41,8 @@ public function testParagraphTypeClass() {
     $this->assertSession()->responseContains('paragraph-type--test-paragraph');
     $this->getSession()->getPage()->findButton('paragraphs_text_add_more')->press();
     $this->assertSession()->responseContains('paragraph-type--text');
+    $this->getSession()->getPage()->findButton('paragraphs_0_remove')->press();
+    $this->assertSession()->responseContains('paragraph-type--text');
   }
 
   /**
@@ -74,6 +71,26 @@ public function testSummary() {
     $node = $this->getNodeByTitle('Llama test');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->pageTextContains('<iframe src="https://www.llamatest.neck');
+    $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">&lt;iframe src=');
+    // Assert that the summary keeps showing html even with longer html.
+    $this->getSession()->getPage()->pressButton('paragraphs_0_edit');
+    $edit = [
+      'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe>',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->assertSession()->pageTextContains('paragraphed_test Llama test has been updated.');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->pageTextContains('<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-');
+    $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">&lt;iframe src=');
+    // Asset that the summary does not display markup even when we have long
+    // html.
+    $this->getSession()->getPage()->pressButton('paragraphs_0_edit');
+    $edit = [
+      'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe><h1>This is a title</h1>',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a title');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php
index 538f100299..3af2a108d6 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php
@@ -2,10 +2,7 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
-use Drupal\Tests\BrowserTestBase;
-use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
-use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\node\Entity\Node;
 
@@ -14,11 +11,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalWidgetButtonsTest extends BrowserTestBase {
-
-  use LoginAdminTrait;
-  use ParagraphsCoreVersionUiTestTrait;
-  use ParagraphsTestBaseTrait;
+class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase {
 
   /**
    * Modules to enable.
@@ -476,6 +469,42 @@ public function testClosedModeThreshold() {
     $this->checkParagraphInMode('field_paragraphs_1', 'edit');
   }
 
+  /**
+   * Tests 'Select list' add mode logic.
+   */
+  public function testAddModeSelect() {
+    $this->loginAsAdmin();
+    $this->addParagraphedContentType('paragraphed_test', 'paragraphs');
+
+    $this->addParagraphsType('test_paragraph');
+    $this->addParagraphsType('text');
+    $this->addFieldtoParagraphType('text', 'field_text_demo', 'text');
+    $settings = [
+      'add_mode' => 'select',
+      'edit_mode' => 'closed',
+      'closed_mode' => 'summary',
+    ];
+    $this->setParagraphsWidgetSettings('paragraphed_test', 'paragraphs', $settings, 'paragraphs');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->assertSession()->selectExists('paragraphs[add_more][add_more_select]');
+
+    $edit = [
+      'settings[handler_settings][negate]' => 0,
+      'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
+    ];
+    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs', $edit, 'Save settings');
+
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->assertSession()->fieldNotExists('paragraphs[add_more][add_more_select]');
+    $this->getSession()->getPage()->findButton('paragraphs_add_more')->press();
+    $edit = [
+      'title[0][value]' => 'Demo text title',
+      'paragraphs[0][subform][field_text_demo][0][value]' => 'Demo text for the detail page',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->assertSession()->pageTextContains('Demo text for the detail page');
+  }
+
   /**
    * Asserts that a paragraph is in a particular mode.
    *
diff --git a/web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
similarity index 76%
rename from web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php
rename to web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
index c60b0cb51b..b09f181360 100644
--- a/web/modules/paragraphs/src/Tests/ParagraphsUninstallTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\paragraphs\Tests;
+namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
 
 /**
  * Tests that Paragraphs module can be uninstalled.
  *
  * @group paragraphs
  */
-class ParagraphsUninstallTest extends WebTestBase {
+class ParagraphsUninstallTest extends BrowserTestBase {
 
   /**
    * Modules to enable.
@@ -18,6 +18,11 @@ class ParagraphsUninstallTest extends WebTestBase {
    */
   public static $modules = array('paragraphs_demo');
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -41,16 +46,16 @@ public function testUninstall() {
     $this->drupalPostForm(NULL, [], t('Uninstall'));
 
     // Delete library data.
-    $this->clickLink('Remove paragraphs library item entities');
-    $this->drupalPostForm(NULL, [], t('Delete all paragraphs library item entities'));
+    $this->clickLink('Remove Paragraphs library items');
+    $this->drupalPostForm(NULL, [], t('Delete all Paragraphs library items'));
 
     // Uninstall the library module.
     $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs_library]' => TRUE], t('Uninstall'));
     $this->drupalPostForm(NULL, [], t('Uninstall'));
 
     // Delete paragraphs data.
-    $this->clickLink('Remove paragraph entities');
-    $this->drupalPostForm(NULL, [], t('Delete all paragraph entities'));
+    $this->clickLink('Remove Paragraphs');
+    $this->drupalPostForm(NULL, [], t('Delete all Paragraphs'));
 
     // Uninstall the module paragraphs.
     $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs]' => TRUE], t('Uninstall'));
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php
index ac1c2e62e0..1d508adb94 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php
@@ -3,16 +3,16 @@
 namespace Drupal\Tests\paragraphs\FunctionalJavascript;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 
 /**
  * Test paragraphs user interface.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAddWidgetTest extends JavascriptTestBase {
+class ParagraphsExperimentalAddWidgetTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use FieldUiTestTrait;
@@ -34,6 +34,11 @@ class ParagraphsExperimentalAddWidgetTest extends JavascriptTestBase {
     'link',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -83,15 +88,24 @@ public function testAddWidgetButton() {
     $icon_two = $this->addParagraphsTypeIcon('text');
 
     // Add a text field to the text_paragraph type.
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'text_long');
+    $page->fillField('label', 'Text');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'text');
+    $page->pressButton('Save and continue');
 
     // Create paragraph type Nested test.
     $this->addParagraphsType('nested_test');
 
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_test', 'paragraphs', 'Paragraphs', 'entity_reference_revisions', [
-      'settings[target_type]' => 'paragraph',
-      'cardinality' => '-1',
-    ], []);
+    $this->drupalGet('/admin/structure/paragraphs_type/nested_test/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph');
+    $page->fillField('label', 'Paragraphs');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'paragraphs');
+    $page->pressButton('Save and continue');
 
     // Set the settings for the field in the nested paragraph.
     $component = [
@@ -112,7 +126,8 @@ public function testAddWidgetButton() {
     $page->pressButton('Add Paragraph');
     $this->assertSession()->assertWaitOnAjaxRequest();
     $this->assertSession()->elementTextContains('css', '.ui-dialog-title', 'Add Paragraph');
-    $page->pressButton('nested_test');
+    $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog');
+    $paragraphs_dialog->pressButton('nested_test');
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Verify that the paragraphs type icons are being displayed.
@@ -136,11 +151,10 @@ public function testAddWidgetButton() {
     ];
     $this->drupalPostForm(NULL, $edit, t('Save'));
 
-
     // Check the created paragraphed test.
-    $this->assertText('paragraphed_test Example title has been created.');
-    $this->assertRaw('paragraph--type--nested-test');
-    $this->assertRaw('paragraph--type--text');
+    $this->assertSession()->pageTextContainsOnce('paragraphed_test Example title has been created.');
+    $this->assertSession()->elementTextContains('css', '.paragraph--type--nested-test', 'Paragraphs');
+    $this->assertSession()->elementTextContains('css', '.paragraph--type--text', '');
 
     // Add a paragraphs field with another paragraphs widget title to the
     // paragraphed_test content type.
@@ -198,16 +212,40 @@ public function testModalAddWidgetDelta() {
     $this->addParagraphsType('test_3');
 
     // Add a text field to the text_paragraph type.
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/test_1', 'text_1', 'Text', 'text_long', [], []);
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/test_2', 'text_2', 'Text', 'text_long', [], []);
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/test_3', 'text_3', 'Text', 'text_long', [], []);
+    $this->drupalGet('admin/structure/paragraphs_type/test_1/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'text_long');
+    $page->fillField('label', 'Text');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'text_1');
+    $page->pressButton('Save and continue');
+
+    $this->drupalGet('admin/structure/paragraphs_type/test_2/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'text_long');
+    $page->fillField('label', 'Text');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'text_2');
+    $page->pressButton('Save and continue');
+
+    $this->drupalGet('admin/structure/paragraphs_type/test_3/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'text_long');
+    $page->fillField('label', 'Text');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'test_3');
+    $page->pressButton('Save and continue');
 
     // Create paragraph type Nested test.
     $this->addParagraphsType('test_nested');
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/test_nested', 'paragraphs', 'Paragraphs', 'entity_reference_revisions', [
-      'settings[target_type]' => 'paragraph',
-      'cardinality' => '-1',
-    ], []);
+
+    $this->drupalGet('/admin/structure/paragraphs_type/test_nested/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph');
+    $page->fillField('label', 'Paragraphs');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'paragraphs');
+    $page->pressButton('Save and continue');
 
     // Set the settings for the field in the nested paragraph.
     $component = [
@@ -387,20 +425,19 @@ public function testModalAddWidgetDelta() {
     $this->drupalGet('node/add/test_modal_delta');
     // Add a new Paragraph.
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
-    $this->assertSession()->assertWaitOnAjaxRequest();
-    $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')->click();
+    $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog');
+    $paragraphs_dialog->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')->press();
     $this->assertSession()->assertWaitOnAjaxRequest();
     // Attempt to add a new Paragraph above and cancel.
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
-    $this->assertSession()->assertWaitOnAjaxRequest();
     $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(0)");
     $this->assertSession()->elementExists('css', '.ui-dialog-titlebar-close')->press();
     $delta = $this->getSession()->evaluateScript("jQuery('paragraph-type-add-modal-delta').val()");
     $this->assertEquals($delta, '');
     // Add a new Paragraph with the Add button at the bottom.
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
-    $this->assertSession()->assertWaitOnAjaxRequest();
-    $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->click();
+    $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog');
+    $paragraphs_dialog->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->press();
     $this->assertSession()->assertWaitOnAjaxRequest();
     // The position of it should be below the first added Paragraph.
     $base_paragraphs = $page->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php
index cf14f6628d..cdfd77a050 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php
@@ -2,9 +2,9 @@
 
 namespace Drupal\Tests\paragraphs\FunctionalJavascript;
 
-use Drupal\field_ui\Tests\FieldUiTestTrait;
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
-use Drupal\paragraphs\Tests\Classic\ParagraphsCoreVersionUiTestTrait;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -12,7 +12,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalClientsideButtonsTest extends JavascriptTestBase {
+class ParagraphsExperimentalClientsideButtonsTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use FieldUiTestTrait;
@@ -33,6 +33,11 @@ class ParagraphsExperimentalClientsideButtonsTest extends JavascriptTestBase {
     'link',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -86,10 +91,15 @@ public function testAddParagraphAboveButton() {
     // Add a Paragraph type.
     $this->addParagraphsType('text');
     // Add a text field to the text_paragraph type.
-    static::fieldUIAddNewField('admin/structure/paragraphs_type/text', 'text', 'Text', 'string', [], []);
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $page->selectFieldOption('new_storage_type', 'string');
+    $page->fillField('label', 'Text');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'text');
+    $page->pressButton('Save and continue');
     // Add a paragraphed test.
     $this->drupalGet('node/add/paragraphed_test');
-
     // Add 3 paragraphs.
     $page->pressButton('Add Paragraph');
     $assert_session->assertWaitOnAjaxRequest();
@@ -159,6 +169,15 @@ public function testAddParagraphAboveButton() {
     $dialog = $page->find('xpath', '//div[contains(@class, "ui-dialog")]');
     $dialog->pressButton('text');
     $assert_session->assertWaitOnAjaxRequest();
+    $page->fillField('field_paragraphs[3][subform][field_text][0][value]', 'Paragraph added above');
+
+    // Add a new paragraph in order to test that the new paragraph is added at the bottom.
+    $page->pressButton('Add Paragraph');
+    $assert_session->assertWaitOnAjaxRequest();
+    $dialog = $page->find('xpath', '//div[contains(@class, "ui-dialog")]');
+    $dialog->pressButton('text');
+    $assert_session->assertWaitOnAjaxRequest();
+    $page->fillField('field_paragraphs[4][subform][field_text][0][value]', 'New paragraph');
 
     // First row after insertion.
     $first_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)');
@@ -169,7 +188,7 @@ public function testAddParagraphAboveButton() {
     // Second row after insertion.
     $second_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(2)');
     $text_input_second_row = $assert_session->elementExists('css', 'input.form-text', $second_row);
-    $this->assertEquals('', $text_input_second_row->getValue());
+    $this->assertEquals('Paragraph added above', $text_input_second_row->getValue());
     $delta_paragraph2 = $assert_session->elementExists('css', 'td.delta-order select', $second_row)->getValue();
     $this->assertEquals(1, $delta_paragraph2);
     // Third row after insertion.
@@ -184,6 +203,11 @@ public function testAddParagraphAboveButton() {
     $this->assertEquals('Third text', $text_input_fourth_row->getValue());
     $delta_paragraph4 = $assert_session->elementExists('css', 'td.delta-order select', $fourth_row)->getValue();
     $this->assertEquals(3, $delta_paragraph4);
+    $fifth_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(5)');
+    $text_input_fifth_row = $assert_session->elementExists('css', 'input.form-text', $fifth_row);
+    $this->assertEquals('New paragraph', $text_input_fifth_row->getValue());
+    $delta_paragraph5 = $assert_session->elementExists('css', 'td.delta-order select', $fifth_row)->getValue();
+    $this->assertEquals(4, $delta_paragraph5);
 
     // Let's have more fun with some nested paragraphs.
     $this->addParagraphsType('rich_paragraph');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php
index adfdb81551..99fa178914 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php
@@ -3,16 +3,15 @@
 namespace Drupal\Tests\paragraphs\FunctionalJavascript;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\paragraphs\Entity\ParagraphsType;
 
 /**
  * Test paragraphs user interface.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalEditPerspectivesUiTest extends JavascriptTestBase {
+class ParagraphsExperimentalEditPerspectivesUiTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use ParagraphsTestBaseTrait;
@@ -33,6 +32,11 @@ class ParagraphsExperimentalEditPerspectivesUiTest extends JavascriptTestBase {
     'text',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * {@inheritdoc}
    */
@@ -41,54 +45,75 @@ protected function setUp() {
   }
 
   /**
-   * Test paragraphs user interface.
+   * Tests visibility of elements when switching perspectives.
    */
   public function testEditPerspectives() {
-
     $this->loginAsAdmin([
-      'access content overview',
       'edit behavior plugin settings'
     ]);
 
     $page = $this->getSession()->getPage();
     $this->drupalGet('admin/structure/paragraphs_type/add');
-    $edit = [
-      'label' => 'TestPlugin',
-      'id' => 'testplugin',
-      'behavior_plugins[test_text_color][enabled]' => TRUE,
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
-    $this->drupalGet('admin/structure/types/add');
-    $edit = [
-      'name' => 'TestContent',
-      'type' => 'testcontent',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
-    $this->drupalGet('admin/structure/types/manage/testcontent/fields/add-field');
-    $edit = [
-      'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
-      'label' => 'testparagraphfield',
-      'field_name' => 'testparagraphfield',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-    $edit = [
-      'settings[target_type]' => 'paragraph',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save field settings'));
-    $edit = [
-      'settings[handler_settings][target_bundles_drag_drop][testplugin][enabled]' => TRUE,
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
-    $this->drupalGet('admin/structure/types/manage/testcontent/form-display');
-    $page->selectFieldOption('fields[field_testparagraphfield][type]', 'paragraphs');
-    $this->assertSession()->assertWaitOnAjaxRequest();
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $page->fillField('label', 'TestPlugin');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('id', 'testplugin');
+    $page->checkField('behavior_plugins[test_text_color][enabled]');
+    $page->pressButton('Save and manage fields');
+
+    $this->addParagraphedContentType('testcontent', 'field_testparagraphfield');
+    $this->addFieldtoParagraphType('testplugin', 'body', 'string_long');
+
     $this->drupalGet('node/add/testcontent');
+    $add_wrapper = $page->find('css', '.paragraphs-add-wrapper');
+    $this->assertTrue($add_wrapper->isVisible());
     $this->clickLink('Behavior');
+    $this->assertFalse($add_wrapper->isVisible());
     $style_selector = $page->find('css', '.form-item-field-testparagraphfield-0-behavior-plugins-test-text-color-text-color');
     $this->assertTrue($style_selector->isVisible());
     $this->clickLink('Content');
     $this->assertFalse($style_selector->isVisible());
+
+    // Assert scroll position when switching tabs.
+    $this->getSession()->resizeWindow(800, 500);
+    $this->drupalGet('node/add/testcontent');
+    $button = $this->getSession ()->getPage()->findButton('Add TestPlugin');
+    $button->press();
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $button->press();
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $button->press();
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    // First move to the last paragraph, assert that the tabs are
+    // still visible, then move back up to the second.
+    $this->getSession()->getPage()->find('css', '.field--widget-paragraphs tbody > tr:nth-child(4)')->mouseOver();
+    $this->assertSession()->assertVisibleInViewport('css', '.paragraphs-tabs');
+    $this->getSession()->getPage()->find('css', '.field--widget-paragraphs tbody > tr:nth-child(2)')->mouseOver();
+    $this->getSession()->evaluateScript('window.scrollBy(0, -10);');
+
+    // As a result, only paragraph 2 and 3 are fully visible on the content tab.
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:first-child');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)');
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)');
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field-add-more-submit');
+
+    // When clicking the Behavior tab, paragraph 2, 3 and 4 are in the viewport
+    // because the behavior settings take less space.
+    $this->clickLink('Behavior');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)');
+
+    // When we switch back to the Content tab, we should stay on the same
+    // scroll position as before.
+    $this->clickLink('Content');
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:first-child');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(2)');
+    $this->assertSession()->assertVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(3)');
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field--widget-paragraphs tbody > tr:nth-child(4)');
+    $this->assertSession()->assertNotVisibleInViewport('css', '.field-add-more-submit');
   }
 
   /**
@@ -101,24 +126,27 @@ public function testTabsVisibility() {
 
     $page = $this->getSession()->getPage();
     $this->drupalGet('admin/structure/paragraphs_type/add');
-    $edit = [
-      'label' => 'TestPlugin',
-      'id' => 'testplugin',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $page->fillField('label', 'TestPlugin');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('id', 'testplugin');
+    $page->pressButton('Save and manage fields');
+
     $this->drupalGet('admin/structure/types/add');
-    $edit = [
-      'name' => 'TestContent',
-      'type' => 'testcontent',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $page->fillField('name', 'TestContent');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('type', 'testcontent');
+    $page->pressButton('Save and manage fields');
+
     $this->drupalGet('admin/structure/types/manage/testcontent/fields/add-field');
-    $edit = [
-      'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
-      'label' => 'testparagraphfield',
-      'field_name' => 'testparagraphfield',
-    ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
+    $page->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph');
+    $page->fillField('label', 'testparagraphfield');
+    $this->assertSession()->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
+    $page->pressButton('Edit');
+    $page->fillField('field_name', 'testparagraphfield');
+    $page->pressButton('Save and continue');
+
     $edit = [
       'settings[target_type]' => 'paragraph',
     ];
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php
index e734cb2dbf..1e46df361a 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\Tests\paragraphs\FunctionalJavascript;
 
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\language\Entity\ConfigurableLanguage;
 
 /**
@@ -10,7 +10,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalWidgetElementsTest extends JavascriptTestBase {
+class ParagraphsExperimentalWidgetElementsTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use ParagraphsTestBaseTrait;
@@ -31,6 +31,11 @@ class ParagraphsExperimentalWidgetElementsTest extends JavascriptTestBase {
     'content_translation',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * Test paragraphs drag handler during translation.
    */
@@ -66,8 +71,8 @@ public function testDragHandler() {
     $page = $this->getSession()->getPage();
     $this->drupalGet('node/add/paragraphed_content_demo');
     $page->pressButton('Add Paragraph');
-    $this->assertSession()->assertWaitOnAjaxRequest();
-    $page->pressButton('text');
+    $paragraphs_dialog = $this->assertSession()->waitForElementVisible('css', 'div.ui-dialog');
+    $paragraphs_dialog->pressButton('text');
     $this->assertSession()->assertWaitOnAjaxRequest();
     // Assert the draghandle is visible.
     $style_selector = $page->find('css', '.tabledrag-handle');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
index c317b2f717..201df18ab1 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
@@ -126,7 +126,9 @@ protected function addParagraphsTypeIcon($paragraphs_type) {
 
     // Create a copy of the image, so that multiple file entities don't
     // reference the same file.
-    $copy_uri = file_unmanaged_copy($uri);
+    /** @var \Drupal\Core\File\FileSystemInterface $file_system */
+    $file_system = \Drupal::service('file_system');
+    $copy_uri = $file_system->copy($uri, 'public://' . $file_system->basename($uri));
 
     // Create a new file entity.
     $file_entity = File::create([
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
index ba1baa486c..9dc7e00163 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
@@ -5,7 +5,7 @@
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Cache\Context\CacheContextsManager;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Tests\token\Kernel\KernelTestBase;
+use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
index 7916deb46e..7d2508c9c1 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
@@ -73,7 +73,7 @@ public function testBehaviorSettings() {
 
     // Check the text color plugin settings summary.
     $plugin = $paragraph->getParagraphType()->getBehaviorPlugins()->getEnabled();
-    $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], 'Text color: red');
+    $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], ['label' => 'Text color', 'value' => 'red']);
 
     // Update the value of an specific plugin.
     $paragraph->setBehaviorSettings('test_text_color', ['text_color' => 'blue']);
@@ -85,8 +85,41 @@ public function testBehaviorSettings() {
 
     // Check the text color plugin settings summary.
     $plugin = $paragraph->getParagraphType()->getBehaviorPlugins()->getEnabled();
-    $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], 'Text color: blue');
+    $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], ['label' => 'Text color', 'value' => 'blue']);
 
   }
 
+  /**
+   * Tests uninstalling a behavior plugin providing module.
+   *
+   * @throws \Drupal\Core\Entity\EntityStorageException
+   */
+  public function testBehaviorUninstall() {
+    // Create a paragraph type.
+    $paragraph_type = ParagraphsType::create([
+      'label' => 'test_text',
+      'id' => 'test_text',
+      'behavior_plugins' => [
+        'test_text_color' => [
+          'enabled' => TRUE,
+        ],
+      ],
+    ]);
+    $paragraph_type->save();
+    $dependencies = $paragraph_type->getDependencies();
+    $plugins = $paragraph_type->getBehaviorPlugins()->getInstanceIds();
+    $this->assertSame(['module' => ['paragraphs_test']], $dependencies);
+    $this->assertSame(['test_text_color' => 'test_text_color'], $plugins);
+
+    // Uninstall plugin providing module.
+    $this->container->get('config.manager')->uninstall('module', 'paragraphs_test');
+
+    $paragraph_type = ParagraphsType::load('test_text');
+    $this->assertNotNull($paragraph_type);
+    $dependencies = $paragraph_type->getDependencies();
+    $plugins = $paragraph_type->getBehaviorPlugins()->getInstanceIds();
+    $this->assertSame([], $dependencies);
+    $this->assertSame([], $plugins);
+  }
+
 }
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
index 6eb25db379..93be4840af 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
@@ -3,11 +3,14 @@
 namespace Drupal\Tests\paragraphs\Kernel;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\KernelTests\KernelTestBase;
+use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
+use Drupal\Tests\user\Traits\UserCreationTrait;
 
 /**
  * Tests the collapsed summary options.
@@ -16,6 +19,9 @@
  */
 class ParagraphsCollapsedSummaryTest extends KernelTestBase {
 
+  use EntityReferenceTestTrait;
+  use UserCreationTrait;
+
   /**
    * Modules to enable.
    *
@@ -26,6 +32,7 @@ class ParagraphsCollapsedSummaryTest extends KernelTestBase {
     'user',
     'system',
     'field',
+    'entity_reference',
     'entity_reference_revisions',
     'paragraphs_test',
     'file',
@@ -95,7 +102,7 @@ public function testCollapsedSummaryOptions() {
     // Load the paragraph and assert its stored feature settings.
     $paragraph = Paragraph::load($paragraph->id());
     $this->assertEquals($paragraph->getAllBehaviorSettings(), $feature_settings);
-    $this->assertEquals($paragraph->getSummary(), 'Example text for a text paragraph, Text color: red');
+    $this->assertEquals($paragraph->getSummary(), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Example text for a text paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Text color</span>red</span></div></div>');
 
     // Check the summary and the additional options.
     $paragraph_1 = Paragraph::create([
@@ -103,8 +110,9 @@ public function testCollapsedSummaryOptions() {
       'nested_paragraph_field' => [$paragraph],
     ]);
     $paragraph_1->save();
-    $this->assertEquals($paragraph_1->getSummary(), 'Example text for a text paragraph, Text color: red');
-    $this->assertEquals($paragraph_1->getSummary(['show_behavior_summary' => FALSE]), 'Example text for a text paragraph');
+    // We do not include behavior summaries of nested children in the parent
+    // summary.
+    $this->assertEquals($paragraph_1->getSummary(), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Example text for a text paragraph</span></div></div>');
     $info = $paragraph_1->getIcons();
     $this->assertEquals($info['count']['#prefix'], '<span class="paragraphs-badge" title="1 child">');
     $this->assertEquals($info['count']['#suffix'], '</span>');
@@ -143,13 +151,40 @@ public function testNestedParagraphSummary() {
       'nested_paragraph_field' => [$paragraph_text_2, $paragraph_nested_1],
     ]);
     $paragraph_nested_2->save();
-    $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE]), 'Text paragraph on top level');
-    $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE, 'depth_limit' => 2]), 'Text paragraph on top level, Text paragraph on nested level');
+    $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE]), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Text paragraph on top level</span></div></div>');
+    $this->assertEquals($paragraph_nested_2->getSummary(['show_behavior_summary' => FALSE, 'depth_limit' => 2]), '<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">Text paragraph on top level</span>, <span class="summary-content">Text paragraph on nested level</span></div></div>');
     $info = $paragraph_nested_2->getIcons();
     $this->assertEquals($info['count']['#prefix'], '<span class="paragraphs-badge" title="2 children">');
     $this->assertEquals($info['count']['#suffix'], '</span>');
   }
 
+  /**
+   * Tests multiple entity references are visible in the paragraph summary.
+   */
+  public function testMultipleEntityReferences() {
+    $user1 = $this->createUser([], 'bob');
+    $user2 = $this->createUser([], 'pete');
+    $paragraphs_type = ParagraphsType::create([
+      'label' => 'Multiple entity references',
+      'id' => 'multiple_entity_references',
+    ]);
+    $paragraphs_type->save();
+    $this->createEntityReferenceField('paragraph', 'multiple_entity_references', 'field_user_references', 'Users', 'user', 'default', [], FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
+    EntityFormDisplay::create([
+      'targetEntityType' => 'paragraph',
+      'bundle' => 'multiple_entity_references',
+      'mode' => 'default',
+      'status' => TRUE,
+    ])->setComponent('field_user_references', ['type' => 'options_select'])->save();
+    $paragraph_with_multiple_entity_references = Paragraph::create([
+      'type' => 'multiple_entity_references',
+    ]);
+    $paragraph_with_multiple_entity_references->get('field_user_references')->appendItem($user1->id());
+    $paragraph_with_multiple_entity_references->get('field_user_references')->appendItem($user2->id());
+    $paragraph_with_multiple_entity_references->save();
+    $this->assertEquals('<div class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">bob</span>, <span class="summary-content">pete</span></div></div>', $paragraph_with_multiple_entity_references->getSummary());
+  }
+
   /**
    * Adds a field to a given paragraph type.
    *
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
index c63d894616..4be7c37a80 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\Tests\paragraphs\Kernel;
 
-use Drupal\Core\Entity\Entity;
 use Drupal\Core\Site\Settings;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
new file mode 100644
index 0000000000..c4b7805737
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Kernel;
+
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\node\Entity\Node;
+use Drupal\paragraphs\Entity\Paragraph;
+use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
+
+/**
+ * Tests some methods from the Paragraph entity.
+ *
+ * @group paragraphs
+ */
+class ParagraphsEntityMethodsTest extends KernelTestBase {
+
+  use ParagraphsTestBaseTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var string[]
+   */
+  public static $modules = [
+    'paragraphs',
+    'node',
+    'user',
+    'system',
+    'field',
+    'entity_reference_revisions',
+    'file',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('user');
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('paragraph');
+    $this->installSchema('system', ['sequences']);
+    $this->installSchema('node', ['node_access']);
+    \Drupal::moduleHandler()->loadInclude('paragraphs', 'install');
+  }
+
+  /**
+   * Tests the ::label() behavior on the paragraph entity.
+   */
+  public function testParagraphLabel() {
+    $this->addParagraphedContentType('paragraphed_test');
+    $paragraph_type = 'text_paragraph';
+    $this->addParagraphsType($paragraph_type);
+    $this->addFieldtoParagraphType($paragraph_type, 'field_text', 'string');
+
+    // Create a node with a paragraph.
+    $paragraph = Paragraph::create([
+      'type' => 'text_paragraph',
+      'field_text' => 'Example text that is very long and needs to be shortened.',
+    ]);
+    $paragraph->save();
+    $node = Node::create([
+      'title' => 'Test Node',
+      'type' => 'paragraphed_test',
+      'field_paragraphs' => [
+        $paragraph,
+      ],
+    ]);
+    $node->save();
+
+    $storage = \Drupal::entityTypeManager()->getStorage('paragraph');
+
+    // By this point the label should include the parent entity's label and the
+    // field label.
+    $paragraph = $storage->loadUnchanged($paragraph->id());
+    $this->assertEquals('Test Node > field_paragraphs', $paragraph->label());
+
+    // Create a new revision without the paragraph and verify the label on the
+    // paragraph entity reflects that.
+    /** @var \Drupal\node\NodeInterface $node */
+    $node->set('field_paragraphs', []);
+    $node->setNewRevision(TRUE);
+    $node->save();
+    $paragraph = $storage->loadUnchanged($paragraph->id());
+    $this->assertEquals('Test Node > field_paragraphs (previous revision)', $paragraph->label());
+
+    // Delete the node and check if the label reflects that.
+    $node->delete();
+    $paragraph = $storage->loadUnchanged($paragraph->id());
+    $this->assertEquals('Orphaned text_paragraph: Example text that is very long and needs to be sh…', $paragraph->label());
+
+    $paragraph3 = Paragraph::create([
+      'type' => 'text_paragraph',
+      'field_text' => 'Example text3',
+    ]);
+    $paragraph3->save();
+    $node3 = Node::create([
+      'title' => 'Test Node 3',
+      'type' => 'paragraphed_test',
+      'field_paragraphs' => [
+        $paragraph3,
+      ],
+    ]);
+    $node3->save();
+    $paragraph3 = $storage->loadUnchanged($paragraph3->id());
+    $this->assertEquals('Test Node 3 > field_paragraphs', $paragraph3->label());
+
+    // If we delete the field on the node type, the paragraph becomes orphan.
+    FieldStorageConfig::load('node.field_paragraphs')->delete();
+    \Drupal::service('entity.memory_cache')->deleteAll();
+    $paragraph3 = $storage->loadUnchanged($paragraph3->id());
+    $this->assertEquals('Orphaned text_paragraph: Example text3', $paragraph3->label());
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
index de98760a05..b8a9e21ae2 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
@@ -62,11 +62,6 @@ public function testIsChanged() {
     $paragraph->save();
     $this->assertFalse($paragraph->isChanged(), 'Paragraph::isChanged() found no changes after the entity has been saved.');
 
-    // Update the revision author field, which should be skipped from checking
-    // for changes in Paragraph::isChanged().
-    $paragraph->setRevisionAuthorId(3);
-    $this->assertFalse($paragraph->isChanged(), 'Paragraph::isChanged() found no changes after updating revision_uid field.');
-
     $paragraph->set('text', 'New text');
     $this->assertTrue($paragraph->isChanged(), 'Paragraph::isChanged() found changes after updating text field.');
   }
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
index a7b294fb61..2d2b68a03b 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
@@ -3,7 +3,6 @@
 namespace Drupal\Tests\paragraphs\Kernel;
 
 use Drupal\Core\Entity\Entity;
-use Drupal\Core\Site\Settings;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\node\Entity\Node;
@@ -11,7 +10,6 @@
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\KernelTests\KernelTestBase;
-use Drupal\user\Entity\User;
 
 /**
  * Tests the replication functionality provided by Replicate module.
diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php
new file mode 100644
index 0000000000..f08040b271
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Traits;
+
+/**
+ * Provides helper methods for Drupal 8.3.x and 8.4.x versions.
+ */
+trait ParagraphsCoreVersionUiTestTrait {
+
+  /**
+   * An adapter for 8.3 > 8.4 Save (and (un)publish) node button change.
+   *
+   * Arguments are the same as WebTestBase::drupalPostForm.
+   *
+   * @see \Drupal\simpletest\WebTestBase::drupalPostForm
+   * @see https://www.drupal.org/node/2847274
+   *
+   * @param \Drupal\Core\Url|string $path
+   *   Location of the post form.
+   * @param array $edit
+   *   Field data in an associative array.
+   * @param mixed $submit
+   *   Value of the submit button whose click is to be emulated. For example,
+   * @param array $options
+   *   (optional) Options to be forwarded to the url generator.
+   * @param array $headers
+   *   (optional) An array containing additional HTTP request headers.
+   * @param string $form_html_id
+   *   (optional) HTML ID of the form to be submitted.
+   * @param string $extra_post
+   *   (optional) A string of additional data to append to the POST submission.
+   */
+  protected function paragraphsPostNodeForm($path, $edit, $submit, array $options = [], array $headers = [], $form_html_id = NULL, $extra_post = NULL) {
+    $drupal_version = (float) substr(\Drupal::VERSION, 0, 3);
+    if ($drupal_version > 8.3) {
+      switch ($submit) {
+        case  t('Save and unpublish'):
+          $submit = t('Save');
+          $edit['status[value]'] = FALSE;
+          break;
+
+        case t('Save and publish'):
+          $submit = t('Save');
+          $edit['status[value]'] = TRUE;
+          break;
+
+        case t('Save and keep published (this translation)'):
+          $submit = t('Save (this translation)');
+          break;
+
+        default:
+          $submit = t('Save');
+      }
+    }
+    parent::drupalPostForm($path, $edit, $submit, $options, $headers, $form_html_id, $extra_post);
+  }
+
+}
-- 
GitLab