diff --git a/composer.json b/composer.json
index 729c1a309538bad72b6fbf741e40b702ef42ab10..1cf6e8b9a4adc72d1b03f62a90ec709b5199ae22 100644
--- a/composer.json
+++ b/composer.json
@@ -123,7 +123,7 @@
         "drupal/entity_reference_revisions": "1.3",
         "drupal/externalauth": "1.1",
         "drupal/features": "3.8",
-        "drupal/field_group": "1.0",
+        "drupal/field_group": "3.0-rc1",
         "drupal/field_permissions": "1.0-beta1",
         "drupal/file_browser": "1.1",
         "drupal/focal_point": "1.0-beta6",
diff --git a/composer.lock b/composer.lock
index afe7ff112201e4cf59d423d875fe57a5f279ee5a..b2e677c7df1b19f2ca31fdbec04f63d81b3a4450 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": "f915b3d06c6bf036ff097201bc919a2f",
+    "content-hash": "3caed5dbd094aa4540ec32282a537ca5",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -4704,17 +4704,17 @@
         },
         {
             "name": "drupal/field_group",
-            "version": "1.0.0",
+            "version": "3.0.0-rc1",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_group.git",
-                "reference": "8.x-1.0"
+                "reference": "8.x-3.0-rc1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-1.0.zip",
-                "reference": "8.x-1.0",
-                "shasum": "e8aa3fae5c3c5dec84644bb577996938d638a611"
+                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.0-rc1.zip",
+                "reference": "8.x-3.0-rc1",
+                "shasum": "e291b5468c834a344e9aa6cafd3a76171d473a22"
             },
             "require": {
                 "drupal/core": "*"
@@ -4722,14 +4722,14 @@
             "type": "drupal-module",
             "extra": {
                 "branch-alias": {
-                    "dev-1.x": "1.x-dev"
+                    "dev-3.x": "3.x-dev"
                 },
                 "drupal": {
-                    "version": "8.x-1.0",
-                    "datestamp": "1510352885",
+                    "version": "8.x-3.0-rc1",
+                    "datestamp": "1558647185",
                     "security-coverage": {
-                        "status": "covered",
-                        "message": "Covered by Drupal's security advisory policy"
+                        "status": "not-covered",
+                        "message": "RC releases are not covered by Drupal security advisories."
                     }
                 }
             },
@@ -4762,7 +4762,7 @@
             "description": "Provides the field_group module.",
             "homepage": "https://www.drupal.org/project/field_group",
             "support": {
-                "source": "http://cgit.drupalcode.org/field_group"
+                "source": "https://git.drupalcode.org/project/field_group"
             }
         },
         {
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 13e891702308bb5d72e5c194d563ae69b4fa4bd0..16c9d039d41b25e5dbfa7324e885d5aac0848c8c 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -4845,18 +4845,18 @@
     },
     {
         "name": "drupal/field_group",
-        "version": "1.0.0",
-        "version_normalized": "1.0.0.0",
+        "version": "3.0.0-rc1",
+        "version_normalized": "3.0.0.0-RC1",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/field_group.git",
-            "reference": "8.x-1.0"
+            "reference": "8.x-3.0-rc1"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/field_group-8.x-1.0.zip",
-            "reference": "8.x-1.0",
-            "shasum": "e8aa3fae5c3c5dec84644bb577996938d638a611"
+            "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.0-rc1.zip",
+            "reference": "8.x-3.0-rc1",
+            "shasum": "e291b5468c834a344e9aa6cafd3a76171d473a22"
         },
         "require": {
             "drupal/core": "*"
@@ -4864,14 +4864,14 @@
         "type": "drupal-module",
         "extra": {
             "branch-alias": {
-                "dev-1.x": "1.x-dev"
+                "dev-3.x": "3.x-dev"
             },
             "drupal": {
-                "version": "8.x-1.0",
-                "datestamp": "1510352885",
+                "version": "8.x-3.0-rc1",
+                "datestamp": "1558647185",
                 "security-coverage": {
-                    "status": "covered",
-                    "message": "Covered by Drupal's security advisory policy"
+                    "status": "not-covered",
+                    "message": "RC releases are not covered by Drupal security advisories."
                 }
             }
         },
@@ -4905,7 +4905,7 @@
         "description": "Provides the field_group module.",
         "homepage": "https://www.drupal.org/project/field_group",
         "support": {
-            "source": "http://cgit.drupalcode.org/field_group"
+            "source": "https://git.drupalcode.org/project/field_group"
         }
     },
     {
diff --git a/web/modules/field_group/CHANGELOG.txt b/web/modules/field_group/CHANGELOG.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a9d603fd156e34596688906e2c409cc7c436f1a4
--- /dev/null
+++ b/web/modules/field_group/CHANGELOG.txt
@@ -0,0 +1,17 @@
+8.3.0-beta1, 2017-11-10
+-------------------
+- JS error: Modernizr is not defined.
+- Add the new region property to the schema.
+- Adding Multiple Fields wrapped by a Tabs Group cause maximum execution error.
+- Branch tests are failing.
+- .
+- Creating Duplicate Fieldgroup Name Overwrites Existing Fieldgroup.
+- Field groups are not compatible with field layout. Part 1: Make sure regions are changed when changing layout.
+- Typo in Field Group Formatter Plugin HtmlElement::prerender.
+- Revert "Issue #2846589 by huzooka: Typo in Field Group Formatter Plugin HtmlElement::prerender".
+- Undefined index: form_display.
+- Typo in Field Group Formatter Plugin HtmlElement::prerender.
+- Replace all deprecated uses.
+- MessageWarning: Invalid argument supplied for foreach() in field_group_info_groups() (line 663 of modules/contrib/field_group/field_group.module).
+- Replace removed formBuilder->setError with formstate->setError.
+- Undefined index: id in template_preprocess_fieldset() notice.
diff --git a/web/modules/field_group/README.txt b/web/modules/field_group/README.txt
index 2eb008f5411bb78d2612e4e334f273fffd818b8b..6c7257081159a601f417b3fc02e2491df24e6b17 100644
--- a/web/modules/field_group/README.txt
+++ b/web/modules/field_group/README.txt
@@ -39,6 +39,23 @@ To submit bug reports and feature suggestions, or to track changes:
 4. The field grouping done in managed display will be reflected on the view detail page of the entity, while that done in the managed_form_display will be
 reflected in the add/edit form of the entity.
 
+-- Create field groups --
+This section explains how to create groups of fields according to the type chosen.
+    - Fieldsets : This group of fields makes the internal content in a fieldset.
+                  It is possible to add a title and a caption (which appears at the bottom of the fieldset).
+    - Details : Similar to Fieldsets. You can configure them to be open (normal fieldset) or collapsed.
+    - Html element : This fieldgroup renders the inner content in a HTML element.
+                     You can configure attributes and label element.
+The following two groupings works differently because you must associate them with an other grouping.
+    - Accordions : This group of fields makes the child groups as a jQuery accordion.
+                   As a first step you must create an Accordions group. You can set a label and choose an effect.
+                   Then you can create an Accordion Item as a child. This group can contain fields.
+    - Tabs : This fieldgroup renders child groups in its own tabs wrapper.
+             As a first step you must create an Tabs group. You can set choose if you want that your tabs are show horizontally or vertically.
+             Then, you can create Tab as a child and choose one to be open by default. This group can contain fields.
+For all groups, you can add id or classes.
+You can also choose if you want to mark a group as required if one of his fields is require (except for Accordions and Tabs : you must passed by their children).
+
 -- MAINTAINERS --
 
 stalski - http://drupal.org/user/322618
@@ -47,4 +64,4 @@ swentel - http://drupal.org/user/107403
 
 -- INSPIRATORS --
 
-yched - http://drupal.org/user/39567
\ No newline at end of file
+yched - http://drupal.org/user/39567
diff --git a/web/modules/field_group/config/schema/field_group.entity_display.schema.yml b/web/modules/field_group/config/schema/field_group.entity_display.schema.yml
index c47e78474b7db1c24deb2ca286d7f1d21d964bf9..a9fe072ec4ea75b1419597c50d5e330e27c17b2b 100644
--- a/web/modules/field_group/config/schema/field_group.entity_display.schema.yml
+++ b/web/modules/field_group/config/schema/field_group.entity_display.schema.yml
@@ -17,6 +17,9 @@ core.entity_view_display.*.*.*.third_party.field_group:
         parent_name:
           type: string
           label: 'The parent group of this group'
+        region:
+          type: string
+          label: 'The region of this group'
         weight:
           type: integer
           label: 'The weight of the group'
@@ -42,6 +45,9 @@ core.entity_form_display.*.*.*.third_party.field_group:
         label:
           type: string
           label: Readable name of the group
+        region:
+          type: string
+          label: 'The region of this group'
         parent_name:
           type: string
           label: 'The parent group of this group'
diff --git a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
index 82b8f274aa0ee9c93cbf30d9dfd14453fc4d4cce..c897f4aac9c5cc103a05b5458e4fdfa9ae18c3a9 100644
--- a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
+++ b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
@@ -55,6 +55,9 @@ field_group.field_group_formatter_plugin.html_element:
     label_element:
       type: string
       label: 'html element tag to be used for the label'
+    label_element_classes:
+      type: string
+      label: 'html classes to be used for the label'
     attributes:
       type: string
       label: 'html attributes for the element'
@@ -86,6 +89,15 @@ field_group.field_group_formatter_plugin.tabs:
   type: field_group.field_group_formatter_plugin.base
   label: 'Mapping for the tab formatter settings'
   mapping:
+    formatter:
+      type: string
+      label: 'default state for the tabs'
+    description:
+      type: string
+      label: 'description of the tabs'
+    required_fields:
+      type: boolean
+      label: 'Mark for required fields'
     direction:
       type: string
       label: 'Direction of the tabs'
@@ -102,4 +114,4 @@ field_group.field_group_formatter_plugin.base:
       label:  'Classes of the fieldgroup'
     id:
       type: string
-      label: 'Html id of the fieldgroup'
\ No newline at end of file
+      label: 'Html id of the fieldgroup'
diff --git a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
index 53f8c6e63f067949f09b67a223b49741bed68da5..96ef3018cfa2657f5c3ba21f7212ca086e9e4b1e 100644
--- a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
@@ -1,14 +1,13 @@
 name: 'Field Group Migrate'
 type: module
 description: 'Provides the ability to migrate field groups from D6/D7 to D8.'
-package: Migrate
-# version: VERSION
+package: Migration
 # core: 8.x
 dependencies:
   - field_group:field_group
 
-# Information added by Drupal.org packaging script on 2017-11-10
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2019-05-23
+version: '8.x-3.0-rc1'
 core: '8.x'
 project: 'field_group'
-datestamp: 1510352889
+datestamp: 1558647188
diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_form_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml
similarity index 100%
rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_form_display.yml
rename to web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml
diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_view_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml
similarity index 100%
rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d6_field_group_entity_view_display.yml
rename to web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml
diff --git a/web/modules/field_group/contrib/field_group_migrate/migration_templates/d7_field_group.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml
similarity index 100%
rename from web/modules/field_group/contrib/field_group_migrate/migration_templates/d7_field_group.yml
rename to web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
index f0b4f3bf5406b586bdd62b7e35a995b4eaec9e49..860f91ad369a79228c6354bf484cd89440fc5370 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
@@ -17,8 +17,8 @@ class FieldGroupEntityFormDisplay extends PerComponentEntityFormDisplay {
   /**
    * {@inheritdoc}
    */
-  public function import(Row $row, array $old_destination_id_values = array()) {
-    $values = array();
+  public function import(Row $row, array $old_destination_id_values = []) {
+    $values = [];
     // array_intersect_key() won't work because the order is important because
     // this is also the return value.
     foreach (array_keys($this->getIds()) as $id) {
@@ -27,6 +27,10 @@ public function import(Row $row, array $old_destination_id_values = array()) {
     $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values[static::MODE_NAME]);
     if (!$entity->isNew()) {
       $settings = $row->getDestinationProperty('field_group');
+      $settings += [
+        'region' => 'content',
+        'parent_name' => '',
+      ];
       $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
       if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
         $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id'));
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
index 2ef0a5d8d2c6f1b641d4db7b32989ea75cf44c10..3277e934c3e3ef5d4502213f0a2262681e4abaa9 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
@@ -17,8 +17,8 @@ class FieldGroupEntityViewDisplay extends PerComponentEntityDisplay {
   /**
    * {@inheritdoc}
    */
-  public function import(Row $row, array $old_destination_id_values = array()) {
-    $values = array();
+  public function import(Row $row, array $old_destination_id_values = []) {
+    $values = [];
     // array_intersect_key() won't work because the order is important because
     // this is also the return value.
     foreach (array_keys($this->getIds()) as $id) {
@@ -28,6 +28,10 @@ public function import(Row $row, array $old_destination_id_values = array()) {
     foreach ($row->getSourceProperty('view_modes') as $view_mode => $settings) {
       $entity = $this->getEntity($values['entity_type'], $values['bundle'], $view_mode);
       if (!$entity->isNew()) {
+        $settings += [
+          'region' => 'content',
+          'parent_name' => '',
+        ];
         $settings = array_merge($row->getDestinationProperty('field_group'), $settings);
         $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
         if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
index 1110f1889f18221f7bdebd6fd0d771b65979b90a..828715ffd8bbebc1cf8168520738d46953b29e4e 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\field_group_migrate\Plugin\migrate\destination\d7\FieldGroup.
- */
-
 namespace Drupal\field_group_migrate\Plugin\migrate\destination\d7;
 
 use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
@@ -23,8 +18,8 @@ class FieldGroup extends DestinationBase {
   /**
    * {@inheritdoc}
    */
-  public function import(Row $row, array $old_destination_id_values = array()) {
-    $values = array();
+  public function import(Row $row, array $old_destination_id_values = []) {
+    $values = [];
     // array_intersect_key() won't work because the order is important because
     // this is also the return value.
     foreach (array_keys($this->getIds()) as $id) {
@@ -34,6 +29,9 @@ public function import(Row $row, array $old_destination_id_values = array()) {
     $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values['mode'], $values['type']);
     if (!$entity->isNew()) {
       $settings = $row->getDestinationProperty('settings');
+      $settings += [
+        'region' => 'content',
+      ];
       $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('group_name'), $settings);
       if (isset($settings['format_type']) && ($settings['format_type'] == 'hidden')) {
         $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('group_name'));
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php
index ef53935fa4a74ee378e235bdddeab1375cf46fa2..6438e5fba6fdbc536e228ed5fd113dbbef2295e4 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d6/FieldGroup.php
@@ -9,7 +9,9 @@
  * Drupal 6 field_group source.
  *
  * @MigrateSource(
- *   id = "d6_field_group"
+ *   id = "d6_field_group",
+ *   source_module = "fieldgroup",
+ *   destination_module = "field_group"
  * )
  */
 class FieldGroup extends DrupalSqlBase {
@@ -19,14 +21,14 @@ class FieldGroup extends DrupalSqlBase {
    */
   public function query() {
     $query = $this->select('content_group', 'g')
-    ->fields('g', [
-      'group_type',
-      'type_name',
-      'group_name',
-      'label',
-      'settings',
-      'weight',
-    ]);
+      ->fields('g', [
+        'group_type',
+        'type_name',
+        'group_name',
+        'label',
+        'settings',
+        'weight',
+      ]);
     return $query;
   }
 
@@ -55,6 +57,9 @@ public function prepareRow(Row $row) {
     return parent::prepareRow($row);
   }
 
+  /**
+   *
+   */
   protected function transformEntityFormDisplaySettings(Row $row) {
     $row->setSourceProperty('extracted_settings', $row->getSourceProperty('settings/form'));
     $source_settings = $row->getSourceProperty('extracted_settings');
@@ -96,6 +101,9 @@ protected function transformEntityFormDisplaySettings(Row $row) {
     $row->setSourceProperty('converted_settings', $settings);
   }
 
+  /**
+   *
+   */
   protected function transformEntityViewDisplaySettings(Row $row) {
     $row->setSourceProperty('extracted_settings', $row->getSourceProperty('settings/display'));
     $view_modes = array_diff(array_keys($row->getSourceProperty('extracted_settings')), ['label', 'description', 'weight']);
@@ -150,7 +158,7 @@ protected function transformEntityViewDisplaySettings(Row $row) {
         $view_mode = 'default';
       }
 
-      // $row->setSourceProperty('view_modes/' . $view_mode, $settings);
+      // $row->setSourceProperty('view_modes/' . $view_mode, $settings);.
       $view_modes[$view_mode] = $settings;
     }
 
@@ -180,7 +188,7 @@ public function fields() {
       'group_name',
       'label',
       'settings',
-      'weight'
+      'weight',
     ];
     return array_combine($fields, $fields);
   }
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
index dc69ec2bf561e642c8abeee05818a1628d5da16d..4825c845948f1447df4eac28a0ae2c69d3858103 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\field_group_migrate\Plugin\migrate\source\d7\FieldGroup.
- */
-
 namespace Drupal\field_group_migrate\Plugin\migrate\source\d7;
 
 use Drupal\migrate\Row;
@@ -14,7 +9,9 @@
  * Drupal 7 field_group source.
  *
  * @MigrateSource(
- *   id = "d7_field_group"
+ *   id = "d7_field_group",
+ *   source_module = "field_group",
+ *   destination_module = "field_group"
  * )
  */
 class FieldGroup extends DrupalSqlBase {
@@ -33,14 +30,15 @@ public function prepareRow(Row $row) {
     $data = unserialize($row->getSourceProperty('data'));
     $format_settings = $data['format_settings'] + $data['format_settings']['instance_settings'];
     unset($format_settings['instance_settings']);
-    $settings = array(
+    $settings = [
       'children' => $data['children'],
       'parent_name' => $row->getSourceProperty('parent_name'),
       'weight' => $data['weight'],
       'label' => $data['label'],
       'format_settings' => $format_settings,
       'format_type' => $data['format_type'],
-    );
+      'region' => 'content',
+    ];
     switch ($data['format_type']) {
       case 'div':
         $settings['format_type'] = 'html_element';
@@ -67,7 +65,7 @@ public function prepareRow(Row $row) {
         break;
 
       case 'multipage':
-      // @todo Check if there is a better way to deal with this format type.
+        // @todo Check if there is a better way to deal with this format type.
         $settings['format_type'] = 'tab';
         break;
 
@@ -88,7 +86,7 @@ public function getIds() {
    * {@inheritdoc}
    */
   public function fields() {
-    $fields = array(
+    $fields = [
       'id' => $this->t('ID'),
       'identifier' => $this->t('Identifier'),
       'group_name' => $this->t('Group name'),
@@ -96,8 +94,9 @@ public function fields() {
       'bundle' => $this->t('Bundle'),
       'mode' => $this->t('View mode'),
       'parent_name' => $this->t('Parent name'),
+      'region' => $this->t('Region'),
       'data' => $this->t('Data'),
-    );
+    ];
     return $fields;
   }
 
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php b/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php
index f418f173a6b1272568601091d942b61bb9133fbb..347b5f73ff5e353237ba3c7f7b9d2a92150690a9 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/fixtures/drupal7.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * A database agnostic dump for testing purposes.
@@ -8,140 +9,165 @@
 
 $connection = Database::getConnection();
 
-$connection->schema()->createTable('field_group', array(
-  'fields' => array(
-    'id' => array(
+$connection->schema()->createTable('field_group', [
+  'fields' => [
+    'id' => [
       'type' => 'serial',
       'not null' => TRUE,
       'size' => 'normal',
-    ),
-    'identifier' => array(
+    ],
+    'identifier' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '255',
       'default' => '',
-    ),
-    'group_name' => array(
+    ],
+    'group_name' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '32',
       'default' => '',
-    ),
-    'entity_type' => array(
+    ],
+    'entity_type' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '32',
       'default' => '',
-    ),
-    'bundle' => array(
+    ],
+    'bundle' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '128',
       'default' => '',
-    ),
-    'mode' => array(
+    ],
+    'mode' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '128',
       'default' => '',
-    ),
-    'parent_name' => array(
+    ],
+    'parent_name' => [
       'type' => 'varchar',
       'not null' => TRUE,
       'length' => '32',
       'default' => '',
-    ),
-    'data' => array(
+    ],
+    'data' => [
       'type' => 'blob',
       'not null' => TRUE,
       'size' => 'big',
-    ),
-  ),
-  'primary key' => array(
+    ],
+  ],
+  'primary key' => [
     'id',
-  ),
-  'unique keys' => array(
-    'identifier' => array(
+  ],
+  'unique keys' => [
+    'identifier' => [
       'identifier',
-    ),
-  ),
-  'indexes' => array(
-    'group_name' => array(
+    ],
+  ],
+  'indexes' => [
+    'group_name' => [
       'group_name',
-    ),
-  ),
+    ],
+  ],
   'mysql_character_set' => 'utf8',
-));
+]);
 
 $connection->insert('field_group')
-->fields(array(
-  'id',
-  'identifier',
-  'group_name',
-  'entity_type',
-  'bundle',
-  'mode',
-  'parent_name',
-  'data',
-))
-->values(array(
-  'id' => '1',
-  'identifier' => 'group_page|node|page|default',
-  'group_name' => 'group_page',
-  'entity_type' => 'node',
-  'bundle' => 'page',
-  'mode' => 'default',
-  'parent_name' => '',
-  'data' => 'a:5:{s:5:"label";s:10:"Node group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
-))
-->values(array(
-  'id' => '2',
-  'identifier' => 'group_user|user|user|default',
-  'group_name' => 'group_user',
-  'entity_type' => 'user',
-  'bundle' => 'user',
-  'mode' => 'default',
-  'parent_name' => '',
-  'data' => 'a:5:{s:5:"label";s:17:"User group parent";s:6:"weight";i:1;s:8:"children";a:0:{}s:11:"format_type";s:3:"div";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
-))
-->values(array(
-  'id' => '3',
-  'identifier' => 'group_user_child|user|user|default',
-  'group_name' => 'group_user_child',
-  'entity_type' => 'user',
-  'bundle' => 'user',
-  'mode' => 'default',
-  'parent_name' => 'group_user',
-  'data' => 'a:5:{s:5:"label";s:16:"User group child";s:6:"weight";i:99;s:8:"children";a:1:{i:0;s:12:"user_picture";}s:11:"format_type";s:4:"tabs";s:15:"format_settings";a:2:{s:5:"label";s:16:"User group child";s:17:"instance_settings";a:2:{s:7:"classes";s:16:"user-group-child";s:2:"id";s:33:"group_article_node_article_teaser";}}}',
-))
-->values(array(
-  'id' => '4',
-  'identifier' => 'group_article|node|article|teaser',
-  'group_name' => 'group_article',
-  'entity_type' => 'node',
-  'bundle' => 'article',
-  'mode' => 'teaser',
-  'parent_name' => '',
-  'data' => 'a:5:{s:5:"label";s:10:"htab group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:1:{s:7:"classes";s:10:"htab-group";}}}',
-))
-->values(array(
-  'id' => '5',
-  'identifier' => 'group_page|node|page|form',
-  'group_name' => 'group_page',
-  'entity_type' => 'node',
-  'bundle' => 'page',
-  'mode' => 'form',
-  'parent_name' => '',
-  'data' => 'a:5:{s:5:"label";s:15:"Node form group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
-))
-->values(array(
-  'id' => '6',
-  'identifier' => 'group_article|node|article|form',
-  'group_name' => 'group_article',
-  'entity_type' => 'node',
-  'bundle' => 'article',
-  'mode' => 'form',
-  'parent_name' => '',
-  'data' => 'a:5:{s:5:"label";s:15:"htab form group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
-))
-->execute();
+  ->fields([
+    'id',
+    'identifier',
+    'group_name',
+    'entity_type',
+    'bundle',
+    'mode',
+    'parent_name',
+    'data',
+  ])
+  ->values([
+    'id' => '1',
+    'identifier' => 'group_page|node|page|default',
+    'group_name' => 'group_page',
+    'entity_type' => 'node',
+    'bundle' => 'page',
+    'mode' => 'default',
+    'parent_name' => '',
+    'data' => 'a:5:{s:5:"label";s:10:"Node group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
+  ])
+  ->values([
+    'id' => '2',
+    'identifier' => 'group_user|user|user|default',
+    'group_name' => 'group_user',
+    'entity_type' => 'user',
+    'bundle' => 'user',
+    'mode' => 'default',
+    'parent_name' => '',
+    'data' => 'a:5:{s:5:"label";s:17:"User group parent";s:6:"weight";i:1;s:8:"children";a:0:{}s:11:"format_type";s:3:"div";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
+  ])
+  ->values([
+    'id' => '3',
+    'identifier' => 'group_user_child|user|user|default',
+    'group_name' => 'group_user_child',
+    'entity_type' => 'user',
+    'bundle' => 'user',
+    'mode' => 'default',
+    'parent_name' => 'group_user',
+    'data' => 'a:5:{s:5:"label";s:16:"User group child";s:6:"weight";i:99;s:8:"children";a:1:{i:0;s:12:"user_picture";}s:11:"format_type";s:4:"tabs";s:15:"format_settings";a:2:{s:5:"label";s:16:"User group child";s:17:"instance_settings";a:2:{s:7:"classes";s:16:"user-group-child";s:2:"id";s:33:"group_article_node_article_teaser";}}}',
+  ])
+  ->values([
+    'id' => '4',
+    'identifier' => 'group_article|node|article|teaser',
+    'group_name' => 'group_article',
+    'entity_type' => 'node',
+    'bundle' => 'article',
+    'mode' => 'teaser',
+    'parent_name' => '',
+    'data' => 'a:5:{s:5:"label";s:10:"htab group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:1:{s:7:"classes";s:10:"htab-group";}}}',
+  ])
+  ->values([
+    'id' => '5',
+    'identifier' => 'group_page|node|page|form',
+    'group_name' => 'group_page',
+    'entity_type' => 'node',
+    'bundle' => 'page',
+    'mode' => 'form',
+    'parent_name' => '',
+    'data' => 'a:5:{s:5:"label";s:15:"Node form group";s:6:"weight";i:0;s:8:"children";a:0:{}s:11:"format_type";s:5:"htabs";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
+  ])
+  ->values([
+    'id' => '6',
+    'identifier' => 'group_article|node|article|form',
+    'group_name' => 'group_article',
+    'entity_type' => 'node',
+    'bundle' => 'article',
+    'mode' => 'form',
+    'parent_name' => '',
+    'data' => 'a:5:{s:5:"label";s:15:"htab form group";s:6:"weight";i:2;s:8:"children";a:1:{i:0;s:11:"field_image";}s:11:"format_type";s:4:"htab";s:15:"format_settings";a:1:{s:17:"instance_settings";a:0:{}}}',
+  ])
+  ->execute();
+
+$connection->insert('system')
+  ->fields([
+    'filename',
+    'name',
+    'type',
+    'owner',
+    'status',
+    'bootstrap',
+    'schema_version',
+    'weight',
+    'info',
+  ])
+  ->values([
+    'filename' => 'sites/all/modules/field_group/field_group.module',
+    'name' => 'field_group',
+    'type' => 'module',
+    'owner' => '',
+    'status' => '1',
+    'bootstrap' => '0',
+    'schema_version' => '7008',
+    'weight' => '1',
+    'info' => 'a:12:{s:4:"name";s:11:"Field Group";s:11:"description";s:67:"Provides the ability to group your fields on both form and display.";s:7:"package";s:6:"Fields";s:12:"dependencies";a:2:{i:0;s:5:"field";i:1;s:6:"ctools";}s:4:"core";s:3:"7.x";s:5:"files";a:2:{i:0;s:25:"tests/field_group.ui.test";i:1;s:30:"tests/field_group.display.test";}s:7:"version";s:7:"7.x-1.5";s:7:"project";s:11:"field_group";s:9:"datestamp";s:10:"1452033709";s:5:"mtime";i:1486548096;s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
+  ])
+  ->execute();
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
index ba8e92a54ad79153e3de5daf3f7994e419212b9a..e83c38d647f7bded812f84164c81174c6636fbc0 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
@@ -117,4 +117,5 @@ public function testFieldGroup() {
     $field_group_settings = $entity->getThirdPartySettings('field_group');
     $this->assertEmpty($field_group_settings);
   }
+
 }
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
index 1150015080b62a101be0168c7b117885f4d07ca6..5a43c278385351bcfce3363de90dea5a123cdf30 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
@@ -2,14 +2,14 @@
 
 namespace Drupal\Tests\field_group_migrate\Unit\Migrate\d7;
 
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
 
 /**
  * Tests D7 field group source plugin.
  *
  * @group field_group
  */
-class FieldGroupTest extends MigrateSqlSourceTestCase {
+class FieldGroupTest extends MigrateSqlSourceTestBase {
 
   const PLUGIN_CLASS = 'Drupal\field_group_migrate\Plugin\migrate\source\d7\FieldGroup';
 
diff --git a/web/modules/field_group/css/field_group.field_ui.css b/web/modules/field_group/css/field_group.field_ui.css
index 7584e99e344f820f2f3e69814717d2bbdab85b8d..9a5754689897b252e937c1afd2d8a6e8c782ccdc 100644
--- a/web/modules/field_group/css/field_group.field_ui.css
+++ b/web/modules/field_group/css/field_group.field_ui.css
@@ -1,4 +1,3 @@
-
 #field-overview tr.field-group .group-label,
 #field-display-overview tr.field-group .group-label {
   font-weight: bold;
@@ -6,9 +5,9 @@
 
 #field-overview tr.static-region,
 #field-display-overview tr.static-region {
-	background-color: #ddd;
+  background-color: #ddd;
 }
 
 #edit-refresh {
-  display:none;
-}
\ No newline at end of file
+  display: none;
+}
diff --git a/web/modules/field_group/field_group.api.php b/web/modules/field_group/field_group.api.php
new file mode 100644
index 0000000000000000000000000000000000000000..0125f5b380f57d5449a63adb11d404b80713c19a
--- /dev/null
+++ b/web/modules/field_group/field_group.api.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Hooks for the field_group module.
+ */
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Pre render the build of the field group element.
+ *
+ * @param array $element
+ *   Group being rendered.
+ * @param object $group
+ *   The Field group info.
+ * @param object $rendering_object
+ *   The entity / form being rendered.
+ */
+function hook_field_group_pre_render(array &$element, &$group, &$rendering_object) {
+  // Add all field_group format types to the js settings.
+  $element['#attached']['drupalSettings']['field_group'] = [
+    $group->format_type => [
+      'mode' => $group->mode,
+      'context' => $group->context,
+      'settings' => $group->format_settings,
+    ],
+  ];
+
+  $element['#weight'] = $group->weight;
+
+  // Call the pre render function for the format type.
+  $manager = Drupal::service('plugin.manager.field_group.formatters');
+  $plugin = $manager->getInstance([
+    'format_type' => $group->format_type,
+    'configuration' => ['label' => $group->label, 'settings' => $group->format_settings],
+    'group' => $group,
+  ]);
+  $plugin->preRender($element, $rendering_object);
+}
+
+/**
+ * Alter the pre_rendered build of the field group element.
+ *
+ * @param array $element
+ *   Group being rendered.
+ * @param object $group
+ *   The Field group info.
+ * @param object $rendering_object
+ *   The entity / form being rendered.
+ */
+function hook_field_group_pre_render_alter(array &$element, &$group, &$rendering_object) {
+  if ($group->format_type == 'htab') {
+    $element['#theme_wrappers'] = [
+      'container' => [
+        '#attributes' => ['class' => 'foobar'],
+      ],
+    ];
+  }
+}
+
+/**
+ * Alter the pre_rendered build of the form.
+ *
+ * @param array $element
+ *   Group being rendered.
+ */
+function hook_field_group_build_pre_render_alter(array &$element) {
+  $form_id = $element['#form_id'];
+  if ($form_id == 'my_example_form' && isset($element['group_example'])) {
+    // Add form states to the field group.
+    $element['group_example']['#states'] = [
+      'visible' => [
+        ':input[name="field_are_you_ok"]' => ['value' => 'yes'],
+      ],
+    ];
+  }
+}
+
+/**
+ * Process the field group.
+ *
+ * @param array $element
+ *   The element being processed.
+ * @param $group
+ *   The group info.
+ * @param $complete_form
+ *   The complete form.
+ */
+function hook_field_group_form_process(array &$element, &$group, &$complete_form) {
+  $element['#states'] = [
+    'visible' => [
+      ':input[name="field_are_you_ok"]' => ['value' => 'yes'],
+    ],
+  ];
+}
+
+/**
+ * Alter the processed build of the group.
+ *
+ * @param array $element
+ *   The element being processed.
+ * @param $group
+ *   The group info.
+ * @param $complete_form
+ *   The complete form.
+ */
+function hook_field_group_form_process_alter(array &$element, &$group, &$complete_form) {
+  $element['#states'] = [
+    'visible' => [
+      ':input[name="field_are_you_ok"]' => ['value' => 'yes'],
+    ],
+  ];
+}
+
+/**
+ * Alter the form after all groups are processed.
+ *
+ * @param array $element
+ *   The element being processed.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The form state
+ * @param $complete_form
+ *   The complete form.
+ */
+function hook_field_group_form_process_build_alter(array &$element, FormStateInterface $form_state, &$complete_form) {
+  $element['group_example']['#states'] = [
+    'visible' => [
+      ':input[name="field_are_you_ok"]' => ['value' => 'yes'],
+    ],
+  ];
+}
+
+/**
+ * Hook into the deletion event of a fieldgroup.
+ *
+ * @param $group
+ *   The deleted group.
+ */
+function hook_field_group_delete_field_group($group) {
+  // Extra cleanup code.
+}
+
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/web/modules/field_group/field_group.info.yml b/web/modules/field_group/field_group.info.yml
index 5654d7f35f14003a3626acea8d9ebf83352a04ca..d1c746ca45c62b1bfda6f752a519156375650f8d 100644
--- a/web/modules/field_group/field_group.info.yml
+++ b/web/modules/field_group/field_group.info.yml
@@ -6,8 +6,8 @@ package : Fields
 dependencies:
   - drupal:field
 
-# Information added by Drupal.org packaging script on 2017-11-10
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2019-05-23
+version: '8.x-3.0-rc1'
 core: '8.x'
 project: 'field_group'
-datestamp: 1510352889
+datestamp: 1558647188
diff --git a/web/modules/field_group/field_group.install b/web/modules/field_group/field_group.install
new file mode 100644
index 0000000000000000000000000000000000000000..7213f09bc4042c190e2bac05cfcc4f7ac3111346
--- /dev/null
+++ b/web/modules/field_group/field_group.install
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Update hooks for the Field Group module.
+ */
+
+/**
+ * Set the `region` portion of each field group.
+ */
+function field_group_update_8301() {
+  foreach (['entity_form_display', 'entity_view_display'] as $entity_type) {
+    foreach (\Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple() as $display) {
+      /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
+      if (in_array('field_group', $display->getThirdPartyProviders())) {
+        $field_groups = $display->getThirdPartySettings('field_group');
+        $updated = FALSE;
+        foreach ($field_groups as $group_name => $data) {
+          if (!isset($data['region'])) {
+            $data['region'] = 'content';
+            $display->setThirdPartySetting('field_group', $group_name, $data);
+            $updated = TRUE;
+          }
+        }
+        if ($updated) {
+          $display->save();
+        }
+      }
+    }
+  }
+}
diff --git a/web/modules/field_group/field_group.libraries.yml b/web/modules/field_group/field_group.libraries.yml
index 01f43f6ac22f5b68b021200ffd381aaab442f991..e09631b7cec4ca0792d7f3ef06b3ca32c21f624d 100644
--- a/web/modules/field_group/field_group.libraries.yml
+++ b/web/modules/field_group/field_group.libraries.yml
@@ -47,6 +47,8 @@ formatter.tabs:
   version: VERSION
   js:
     formatters/tabs/tabs.js: {}
+  dependencies:
+    - core/modernizr
 
 element.horizontal_tabs:
   version: VERSION
@@ -58,3 +60,4 @@ element.horizontal_tabs:
       formatters/tabs/horizontal-tabs.css: {}
   dependencies:
     - core/drupal.collapse
+    - core/modernizr
diff --git a/web/modules/field_group/field_group.module b/web/modules/field_group/field_group.module
index e85c489e252ccf2500cd4371e1e1ce2a6255e0c5..b2711b240805d924551a9cb6f1f9178dee4ef6ea 100644
--- a/web/modules/field_group/field_group.module
+++ b/web/modules/field_group/field_group.module
@@ -5,6 +5,8 @@
  * Allows administrators to attach custom fields to fieldable types.
  */
 
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\ds\Ds;
 use Drupal\Core\Entity\ContentEntityFormInterface;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -13,8 +15,22 @@
 use Drupal\Core\Form\ConfirmFormInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
+use Drupal\field_group\Element\VerticalTabs;
 
-require_once __DIR__ . '/includes/helpers.inc';
+/**
+ * Implements hook_help().
+ */
+function field_group_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.field_group':
+      $output = '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('Fieldgroup will, as the name implies, group fields together. All fieldable entities will have the possibility to add groups to wrap their fields together. Fieldgroup comes with default HTML wrappers like vertical tabs, horizontal tabs, accordions, fieldsets or div wrappers.') . '</p>';
+      $output .= '<p>' . t('The field group project is a follow-up on the field group module in <a href="@linkcck">CCK</a>. The release will only exist for Drupal 7 release and higher, so since the existence of the Fields API in core.</br>By moving field group to a separate module, this may open some new perspectives.', ['@linkcck' => 'http://drupal.org/project/cck']) . '</p>';
+      $output .= '<h3>' . t('More Information') . '</h3>';
+      $output .= '<p>' . t('For more information about this module please visit the <a href="@link">module page</a>.', ['@link' => 'https://www.drupal.org/project/field_group']) . '</p>';
+      return $output;
+  }
+}
 
 /**
  * Implements hook_theme_registry_alter().
@@ -23,7 +39,7 @@ function field_group_theme_registry_alter(&$theme_registry) {
 
   // Inject field_group_build_entity_groups in all entity theming functions.
   $entity_info = Drupal::entityTypeManager()->getDefinitions();
-  $entity_types = array();
+  $entity_types = [];
   foreach ($entity_info as $entity_type_id => $entity_type) {
     if ($route_name = $entity_type->get('field_ui_base_route')) {
       $entity_types[] = $entity_type_id;
@@ -47,36 +63,32 @@ function field_group_theme_registry_alter(&$theme_registry) {
  * Implements hook_theme().
  */
 function field_group_theme() {
-  return array(
-    'horizontal_tabs' => array(
+  return [
+    'horizontal_tabs' => [
       'render element' => 'element',
       'template' => 'horizontal-tabs',
       'file' => 'templates/theme.inc',
-    ),
-    'field_group_accordion_item' => array(
+    ],
+    'field_group_accordion_item' => [
       'render element' => 'element',
       'template' => 'field-group-accordion-item',
       'file' => 'templates/theme.inc',
-    ),
-    'field_group_accordion' => array(
+    ],
+    'field_group_accordion' => [
       'render element' => 'element',
       'template' => 'field-group-accordion',
       'file' => 'templates/theme.inc',
-    ),
-    'field_group_html_element' => array(
+    ],
+    'field_group_html_element' => [
       'render element' => 'element',
       'template' => 'field-group-html-element',
       'file' => 'templates/theme.inc',
-    ),
-  );
+    ],
+  ];
 }
 
 /**
  * Implements hook_theme_suggestions_alter().
- *
- * @param array $suggestions
- * @param array $variables
- * @param $hook
  */
 function field_group_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
   switch ($hook) {
@@ -86,9 +98,9 @@ function field_group_theme_suggestions_alter(array &$suggestions, array $variabl
     case 'field_group_html_element':
       $element = $variables['element'];
 
-      $name = $element['#group_name'];
-      $entity_type = $element['#entity_type'];
-      $bundle = $element['#bundle'];
+      $name = !empty($element['#group_name']) ? $element['#group_name'] : NULL;
+      $entity_type = !empty($element['#entity_type']) ? $element['#entity_type'] : NULL;
+      $bundle = !empty($element['#bundle']) ? $element['#bundle'] : NULL;
 
       $wrapper = '';
       if (isset($element['#wrapper_element'])) {
@@ -96,26 +108,58 @@ function field_group_theme_suggestions_alter(array &$suggestions, array $variabl
         $suggestions[] = $hook . '__' . $wrapper;
       }
 
-      $suggestions[] = $hook . '__' . $entity_type;
-      $suggestions[] = $hook . '__' . $bundle;
-      $suggestions[] = $hook . '__' . $name;
+      if (!empty($entity_type)) {
+        $suggestions[] = $hook . '__' . $entity_type;
+      }
+      if (!empty($bundle)) {
+        $suggestions[] = $hook . '__' . $bundle;
+      }
+      if (!empty($name)) {
+        $suggestions[] = $hook . '__' . $name;
+      }
 
-      if ($wrapper) {
+      if ($wrapper && !empty($entity_type)) {
         $suggestions[] = $hook . '__' . $entity_type . '__' . $wrapper;
       }
 
-      $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle;
-      $suggestions[] = $hook . '__' . $entity_type . '__' . $name;
+      if (!empty($entity_type) && !empty($bundle)) {
+        $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle;
+      }
+      if (!empty($entity_type) && !empty($name)) {
+        $suggestions[] = $hook . '__' . $entity_type . '__' . $name;
+      }
 
-      if ($wrapper) {
+      if ($wrapper && !empty($entity_type) && !empty($bundle)) {
         $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $wrapper;
       }
-      $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $name;
+      if (!empty($entity_type) && !empty($bundle) && !empty($name)) {
+        $suggestions[] = $hook . '__' . $entity_type . '__' . $bundle . '__' . $name;
+      }
       break;
   }
 
 }
 
+/**
+ * Implements hook_element_info_alter().
+ */
+function field_group_element_info_alter(array &$info) {
+  // Core does not support #group options on vertical tabs. Add support for it.
+  if (isset($info['vertical_tabs'])) {
+
+    if (!isset($info['vertical_tabs']['#process'])) {
+      $info['vertical_tabs']['#process'] = [];
+    }
+
+    if (!isset($info['vertical_tabs']['#pre_render'])) {
+      $info['vertical_tabs']['#pre_render'] = [];
+    }
+
+    $info['vertical_tabs']['#process'][] = [VerticalTabs::class, 'processGroup'];
+    $info['vertical_tabs']['#pre_render'][] = [VerticalTabs::class, 'preRenderGroup'];
+  }
+}
+
 /**
  * Implements hook_form_FORM_ID_alter().
  * Using hook_form_field_ui_form_display_overview_form_alter.
@@ -141,7 +185,7 @@ function field_group_field_info_max_weight($entity_type, $bundle, $context, $con
 
   $groups = field_group_info_groups($entity_type, $bundle, $context, $context_mode);
 
-  $weights = array();
+  $weights = [];
   foreach ($groups as $group) {
     $weights[] = $group->weight;
   }
@@ -157,24 +201,24 @@ function field_group_form_alter(array &$form, FormStateInterface $form_state) {
   if ($form_object instanceof ContentEntityFormInterface && !$form_object instanceof ConfirmFormInterface) {
 
     /**
-     * @var EntityFormDisplayInterface $form_display
+     * @var \Drupal\Core\Entity\Entity\EntityFormDisplayInterface $form_display
      */
     $storage = $form_state->getStorage();
     if (!empty($storage['form_display'])) {
       $form_display = $storage['form_display'];
       $entity = $form_object->getEntity();
 
-      $context = array(
+      $context = [
         'entity_type' => $entity->getEntityTypeId(),
         'bundle' => $entity->bundle(),
         'entity' => $entity,
         'context' => 'form',
         'display_context' => 'form',
         'mode' => $form_display->getMode(),
-      );
+      ];
 
       field_group_attach_groups($form, $context);
-      $form['#pre_render'][] = 'field_group_form_pre_render';
+      $form['#process'][] = 'field_group_form_process';
     }
   }
 
@@ -195,7 +239,7 @@ function field_group_inline_entity_form_entity_form_alter(&$entity_form, FormSta
   ];
 
   field_group_attach_groups($entity_form, $context);
-  $entity_form['#pre_render'][] = 'field_group_form_pre_render';
+  $entity_form['#process'][] = 'field_group_form_process';
 }
 
 /**
@@ -203,13 +247,13 @@ function field_group_inline_entity_form_entity_form_alter(&$entity_form, FormSta
  */
 function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityDisplayInterface $display) {
 
-  $context = array(
+  $context = [
     'entity_type' => $display->getTargetEntityTypeId(),
     'bundle' => $entity->bundle(),
     'entity' => $entity,
     'display_context' => 'view',
     'mode' => $display->getMode(),
-  );
+  ];
 
   field_group_attach_groups($build, $context);
 
@@ -217,11 +261,11 @@ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityD
   // Add a prerender.
   if (empty($build['#theme'])) {
 
-    $ds_enabled = false;
+    $ds_enabled = FALSE;
     if (Drupal::moduleHandler()->moduleExists('ds')) {
       // Check if DS is enabled for this display.
-      if ($display->getThirdPartySetting('ds', 'layout') && !Drupal\ds\Ds::isDisabled()) {
-        $ds_enabled = true;
+      if ($display->getThirdPartySetting('ds', 'layout') && !Ds::isDisabled()) {
+        $ds_enabled = TRUE;
       }
     }
 
@@ -234,70 +278,181 @@ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityD
 
 /**
  * Pre render callback for rendering groups.
- * @see field_group_field_attach_form
- * @param $element Form that is being rendered.
+ *
+ * @param array $element
+ *   Form that is being rendered.
+ *
+ * @deprecated Use field_group_form_process instead.
+ */
+function field_group_form_pre_render(array $element) {
+  return field_group_form_process($element);
+}
+
+/**
+ * Process callback for field groups.
+ *
+ * @param array $element
+ *   Form that is being processed.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
+ * @param array $form
+ *   The complete form structure.
+ *
+ * @return array
  */
-function field_group_form_pre_render($element) {
-  if (empty($element['#field_group_form_pre_render'])) {
-    $element['#field_group_form_pre_render'] = TRUE;
-    field_group_build_entity_groups($element, 'form');
+function field_group_form_process(array &$element, FormStateInterface $form_state = NULL, array &$form = []) {
+  if (empty($element['#field_group_form_process'])) {
+    $element['#field_group_form_process'] = TRUE;
+    if (empty($element['#fieldgroups'])) {
+      return $element;
+    }
+
+    // Create all groups and keep a flat list of references to these groups.
+    $group_references = [];
+    foreach ($element['#fieldgroups'] as $group_name => $group) {
+      if (!isset($element[$group_name])) {
+        $element[$group_name] = [];
+      }
+
+      $group_parents = $element['#array_parents'];
+      $group_parents[] = empty($group->parent_name) ? $group->region : $group->parent_name;
+      $group_references[$group_name] = &$element[$group_name];
+      $element[$group_name]['#group'] = implode('][', $group_parents);
+
+      // Use array parents to set the group name. This will cover multilevel forms (eg paragraphs).
+      $parents = $element['#array_parents'];
+      $parents[] = $group_name;
+      $element[$group_name]['#parents'] = $parents;
+      $group_children_parent_group = implode('][', $parents);
+      foreach ($group->children as $child) {
+        $element[$child]['#group'] = $group_children_parent_group;
+      }
+    }
+
+    foreach ($element['#fieldgroups'] as $group_name => $group) {
+      $field_group_element = &$element[$group_name];
+
+      // Let modules define their wrapping element.
+      // Note that the group element has no properties, only elements.
+      foreach (Drupal::moduleHandler()->getImplementations('field_group_form_process') as $module) {
+        // The intention here is to have the opportunity to alter the
+        // elements, as defined in hook_field_group_formatter_info.
+        // Note, implement $element by reference!
+        $function = $module . '_field_group_form_process';
+        $function($field_group_element, $group, $element);
+      }
+
+      // Allow others to alter the pre_render.
+      Drupal::moduleHandler()->alter('field_group_form_process', $field_group_element, $group, $element);
+    }
+
+    // Allow others to alter the complete processed build.
+    Drupal::moduleHandler()->alter('field_group_form_process_build', $element, $form_state, $form);
   }
+
   return $element;
 }
 
 /**
  * Pre render callback for rendering groups on entities without theme hook.
- * @param $element
+ *
+ * @param array $element
  *   Entity being rendered.
  */
-function field_group_entity_view_pre_render($element) {
+function field_group_entity_view_pre_render(array $element) {
   field_group_build_entity_groups($element, 'view');
   return $element;
 }
 
+/**
+ * Implements hook_field_group_form_process().
+ */
+function field_group_field_group_form_process(array &$element, &$group, &$complete_form) {
+  // Add all field_group format types to the js settings.
+  $element['#attached']['drupalSettings']['field_group'] = [
+    $group->format_type => [
+      'mode' => $group->mode,
+      'context' => $group->context,
+      'settings' => $group->format_settings,
+    ],
+  ];
+
+  $element['#weight'] = $group->weight;
+
+  // Call the pre render function for the format type.
+  $manager = Drupal::service('plugin.manager.field_group.formatters');
+  $plugin = $manager->getInstance([
+    'format_type' => $group->format_type,
+    'configuration' => ['label' => $group->label, 'settings' => $group->format_settings],
+    'group' => $group,
+  ]);
+  if ($plugin) {
+    $plugin->process($element, $complete_form);
+  }
+}
+
 /**
  * Implements hook_field_group_pre_render().
  *
- * @param Array $element
+ * @param array $element
  *   Group beïng rendered.
- * @param Object $group
+ * @param object $group
  *   The Field group info.
  * @param $rendering_object
  *   The entity / form beïng rendered
  */
 function field_group_field_group_pre_render(&$element, &$group, &$rendering_object) {
-
   // Add all field_group format types to the js settings.
-  $element['#attached']['drupalSettings']['field_group'] = array(
+  $element['#attached']['drupalSettings']['field_group'] = [
     $group->format_type => [
       'mode' => $group->mode,
       'context' => $group->context,
       'settings' => $group->format_settings,
     ],
-  );
+  ];
 
   $element['#weight'] = $group->weight;
 
   // Call the pre render function for the format type.
   $manager = Drupal::service('plugin.manager.field_group.formatters');
-  $plugin = $manager->getInstance(array(
+  $plugin = $manager->getInstance([
     'format_type' => $group->format_type,
-    'configuration' => array('label' => $group->label, 'settings' => $group->format_settings),
+    'configuration' => [
+      'label' => $group->label,
+      'settings' => $group->format_settings,
+    ],
     'group' => $group,
-  ));
-  $plugin->preRender($element, $rendering_object);
+  ]);
+  if ($plugin) {
+    $plugin->preRender($element, $rendering_object);
+  }
+}
 
+/**
+ * Implements hook_field_group_form_process_build_alter().
+ *
+ * @param array $element
+ *   Element being processed.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
+ * @param array $form
+ *   The complete form structure.
+ */
+function field_group_field_group_form_process_build_alter(array &$element, $form_state = NULL, &$form = []) {
+  $groups = array_keys($element['#fieldgroups']);
+  field_group_remove_empty_form_groups($element, $groups, $element['#entity_type']);
 }
 
 /**
  * Implements hook_field_group_build_pre_render_alter().
- * @param Array $elements by address.
+ *
+ * @param array $elements
+ *   By address.field_group_entity_display_build_alter
  */
 function field_group_field_group_build_pre_render_alter(& $element) {
-
   // Someone is doing a node view, in a node view. Reset content.
   if (isset($element['#node']->content) && count($element['#node']->content) > 0) {
-    $element['#node']->content = array();
+    $element['#node']->content = [];
   }
 
   $display = isset($element['#view_mode']);
@@ -307,23 +462,26 @@ function field_group_field_group_build_pre_render_alter(& $element) {
   if ($display) {
     field_group_remove_empty_display_groups($element, $groups);
   }
+  // Remove all empty groups on the form.
   else {
-    // Fix the problem on forms with additional settings.
-    field_group_remove_empty_form_groups('form', $element, $groups, $element['#fieldgroups'], $element['#entity_type']);
+    field_group_remove_empty_form_groups($element, $groups, $element['#entity_type']);
   }
-
 }
 
 /**
  * Attach groups to the (form) build.
  *
- * @param Array $element
+ * @param array $element
  *   The part of the form.
- *  @param Array $context
+ * @param array $context
  *   The contextual information.
  */
 function field_group_attach_groups(&$element, $context) {
 
+  if ($context['mode'] == '_custom') {
+    return;
+  }
+
   $entity_type = $context['entity_type'];
   $bundle = $context['bundle'];
   $mode = $context['mode'];
@@ -332,7 +490,7 @@ function field_group_attach_groups(&$element, $context) {
   $element['#fieldgroups'] = field_group_info_groups($entity_type, $bundle, $display_context, $mode);
 
   // Create a lookup array.
-  $group_children = array();
+  $group_children = [];
   foreach ($element['#fieldgroups'] as $group_name => $group) {
     foreach ($group->children as $child) {
       $group_children[$child] = $group_name;
@@ -340,110 +498,115 @@ function field_group_attach_groups(&$element, $context) {
   }
   $element['#group_children'] = $group_children;
   $element['#entity_type'] = $entity_type;
-
 }
 
 /**
- * Preprocess/ Pre-render callback.
+ * Pre-render callback for entity views.
+ *
+ * @param preprocess $vars
+ *   Variables.
+ * @param $context
+ *   The display context (entity type, form or view).
+ *
+ * @return array
+ *   With re-arranged fields in groups.
  *
- * @see field_group_form_pre_render()
  * @see field_group_theme_registry_alter
  * @see field_group_fields_nest()
- * @param $vars preprocess vars or form element
- * @param $context The display context (entity type, form or view)
- * @return $element Array with re-arranged fields in groups.
  */
-function field_group_build_entity_groups(&$vars, $context = 'view') {
-
-  if ($context == 'form') {
-    $element = &$vars;
-    $nest_vars = NULL;
+function field_group_build_entity_groups(array &$vars, $context = 'view') {
+  if (isset($vars['elements'])) {
+    $element = &$vars['elements'];
+  }
+  elseif (isset($vars['content'])) {
+    $element = &$vars['content'];
   }
   else {
-    if (isset($vars['elements'])) {
-      $element = &$vars['elements'];
-    }
-    elseif (isset($vars['content'])) {
-      $element = &$vars['content'];
+    if ($context === 'eck_entity') {
+      $element = &$vars['entity'];
     }
     else {
-      if ($context === 'eck_entity') {
-        $element = &$vars['entity'];
-      }
-      else {
-        $element = &$vars;
-      }
+      $element = &$vars;
     }
-
-    $nest_vars = &$vars;
   }
 
+  $nest_vars = &$vars;
+
   // No groups on the entity.
   if (empty($element['#fieldgroups'])) {
     return $element;
   }
 
-  // Nest the fields in the corresponding field groups.
-  field_group_fields_nest($element, $nest_vars, $context);
+  // Use other nest function if field layout is active.
+  if (isset($element['_field_layout'])) {
+    field_group_field_layout_fields_nest($element, $nest_vars, $context);
+  }
+  else {
+    field_group_fields_nest($element, $nest_vars, $context);
+  }
 
   // Allow others to alter the pre_rendered build.
   Drupal::moduleHandler()->alter('field_group_build_pre_render', $element);
 
-  // Return the element on forms.
-  if ($context == 'form') {
-    return $element;
-  }
-
   // No groups on the entity. Prerender removed empty field groups.
   if (empty($element['#fieldgroups'])) {
     return $element;
   }
 
   // Put groups inside content if we are rendering an entity_view.
+  $render_key = field_group_get_content_element_key($context);
   foreach ($element['#fieldgroups'] as $group) {
     if (!empty($element[$group->group_name])) {
-      $key = field_group_get_content_element_key($context);
-      if (isset($vars[$key])) {
-        $vars[$key][$group->group_name] = $element[$group->group_name];
+      if (isset($vars[$render_key])) {
+        // Field layout enabled? Place it in correct region of the
+        // _field_layout key.
+        if (isset($vars[$render_key]['_field_layout'])) {
+          $vars[$render_key]['_field_layout'][$group->region][$group->group_name] = $element[$group->group_name];
+        }
+        else {
+          $vars[$render_key][$group->group_name] = $element[$group->group_name];
+        }
       }
     }
   }
-
 }
 
 /**
- * Recursive function to nest fields in the field groups.
+ * Nests all the fields in the field groups.
  *
  * This function will take out all the elements in the form and
  * place them in the correct container element, a fieldgroup.
  * The current group element in the loop is passed recursively so we can
  * stash fields and groups in it while we go deeper in the array.
- * @param Array $element
+ *
+ * @param array $element
  *   The current element to analyse for grouping.
- * @param Array $vars
+ * @param array $vars
  *   Rendering vars from the entity being viewed.
- * @param Array $context
+ * @param array $context
  *   The display context (entity type, form or view).
  */
 function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
 
   // Create all groups and keep a flat list of references to these groups.
-  $group_references = array();
+  $group_references = [];
   foreach ($element['#fieldgroups'] as $group_name => $group) {
     // Construct own weight, as some fields (for example preprocess fields) don't have weight set.
-    $element[$group_name] = array();
+    if (!isset($element[$group_name])) {
+      $element[$group_name] = [];
+    }
     $group_references[$group_name] = &$element[$group_name];
   }
 
   // Loop through all form children looking for those that are supposed to be
   // in groups, and insert placeholder element for the new group field in the
   // correct location within the form structure.
-  $element_clone = array();
+  $element_clone = [];
   foreach (Element::children($element) as $child_name) {
     $element_clone[$child_name] = $element[$child_name];
     // If this element is in a group, create the placeholder element.
     if (isset($element['#group_children'][$child_name])) {
-      $element_clone[$element['#group_children'][$child_name]] = array();
+      $element_clone[$element['#group_children'][$child_name]] = [];
     }
   }
   $element = array_merge($element_clone, $element);
@@ -453,11 +616,17 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
   // parent currently is situated.
   foreach ($element['#group_children'] as $child_name => $parent_name) {
 
-    // Entity being viewed
+    // Entity being viewed.
     if ($vars) {
       // If not a group, check the content variable for empty field.
       $key = field_group_get_content_element_key($context);
       if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key][$child_name])) {
+
+        // ECK marks his defaut properties as printed, while it is not printed yet.
+        if ($context === 'eck_entity' && !empty($vars[$key][$child_name]['#printed'])) {
+          $vars[$key][$child_name]['#printed'] = FALSE;
+        }
+
         $group_references[$parent_name][$child_name] = $vars[$key][$child_name];
         unset($vars[$key][$child_name]);
       }
@@ -468,7 +637,7 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
         unset($element[$child_name]);
       }
     }
-    // Form being viewed
+    // Form being viewed.
     else {
       // Block denied fields (#access) before they are put in groups.
       // Fields (not groups) that don't have children (like field_permissions) are removed
@@ -477,6 +646,11 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
         // If this is a group, we have to use a reference to keep the reference
         // list intact (but if it is a field we don't mind).
         $group_references[$parent_name][$child_name] = &$element[$child_name];
+
+        // Remove the #group property, otherwise core will move this element to
+        // the field layout region.
+        unset($group_references[$parent_name][$child_name]['#group']);
+
         $group_references[$parent_name]['#weight'] = $element['#fieldgroups'][$parent_name]->weight;
       }
 
@@ -491,7 +665,76 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
   foreach ($element['#fieldgroups'] as $group_name => $group) {
     field_group_pre_render($group_references[$group_name], $group, $element);
   }
+}
+
+/**
+ * Nests all the fields in the field groups.
+ *
+ * Ror entity display elements managed by field layout.
+ *
+ * @param array $element
+ * @param $vars
+ * @param $context
+ */
+function field_group_field_layout_fields_nest(array &$element, &$vars = NULL, $context = NULL) {
+  // Create all groups and keep a flat list of references to these groups.
+  $group_references = [];
+  foreach ($element['#fieldgroups'] as $group_name => $group) {
+    // Construct own weight, as some fields (for example preprocess fields)
+    // don't have weight set.
+    if (!isset($element[$group_name])) {
+      $element[$group_name] = [];
+    }
+    $group_references[$group_name] = &$element[$group_name];
+  }
+
+  // Loop through all children looking for those that are supposed to be
+  // in groups, and insert placeholder element for the new group field in the
+  // correct location within the form structure.
+  $element_clone = [];
+  foreach (Element::children($element['_field_layout']) as $region_name) {
+    foreach (Element::children($element['_field_layout'][$region_name]) as $child_name) {
+      $element_clone['_field_layout'][$region_name][$child_name] = $element['_field_layout'][$region_name][$child_name];
+      // If this element is in a group, create the placeholder element.
+      if (isset($element['_field_layout'][$region_name]['#group_children'][$child_name])) {
+        $element_clone['_field_layout'][$region_name][$element['#group_children'][$child_name]] = [];
+      }
+    }
+  }
+
+  $element = array_merge($element_clone, $element);
+
+  // Move all children to their parents. Use the flat list of references for
+  // direct access as we don't know where in the root_element hierarchy the
+  // parent currently is situated.
+  foreach ($element['#group_children'] as $child_name => $group_name) {
+    $region = $element['#fieldgroups'][$group_name]->region;
+
+    // If not a group, check the content variable for empty field.
+    $key = field_group_get_content_element_key($context);
+    if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key]['_field_layout'][$region][$child_name])) {
+
+      // ECK marks his defaut properties as printed, while it is not printed yet.
+      if ($context === 'eck_entity' && !empty($vars[$key]['_field_layout'][$region][$child_name]['#printed'])) {
+        $vars[$key]['_field_layout'][$region][$child_name]['#printed'] = FALSE;
+      }
+
+      $group_references[$group_name][$child_name] = $vars[$key]['_field_layout'][$region][$child_name];
+      unset($vars[$key]['_field_layout'][$region][$child_name]);
+    }
+    // If this is a group, we have to use a reference to keep the reference
+    // list intact (but if it is a field we don't mind).
+    else {
+      $group_references[$group_name][$child_name] = &$element[$child_name];
+      unset($element[$child_name]);
+    }
+  }
 
+  // Bring extra element wrappers to achieve a grouping of fields.
+  // This will mainly be prefix and suffix altering.
+  foreach ($element['#fieldgroups'] as $group_name => $group) {
+    field_group_pre_render($group_references[$group_name], $group, $element);
+  }
 }
 
 /**
@@ -509,8 +752,8 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
 function field_group_pre_render(& $element, $group, & $rendering_object) {
 
   // Only run the pre_render function if the group has elements.
-  // $group->group_name
-  if ($element == array()) {
+  // $group->group_name.
+  if ($element == []) {
     return;
   }
 
@@ -554,7 +797,6 @@ function field_group_get_content_element_key($context = 'default') {
   return $key;
 }
 
-
 /**
  * Saves a group definition.
  *
@@ -567,7 +809,7 @@ function field_group_get_content_element_key($context = 'default') {
  * @param \Drupal\Core\Entity\Display\EntityDisplayInterface $display
  *   The display to update if known.
  *
- * @return \Drupal\Core\Entity\Display\EntityDisplayInterface|NULL
+ * @return \Drupal\Core\Entity\Display\EntityDisplayInterface|null
  *   The updated entity display.
  */
 function field_group_group_save($group, $display = NULL) {
@@ -583,23 +825,26 @@ function field_group_group_save($group, $display = NULL) {
   // If no display was found. It doesn't exist yet, create it.
   if (!isset($display)) {
     if ($group->context == 'form') {
-      $display = EntityFormDisplay::create(array(
+      $display = EntityFormDisplay::create([
         'targetEntityType' => $group->entity_type,
         'bundle' => $group->bundle,
         'mode' => $group->mode,
-      ))->setStatus(TRUE);
+      ])->setStatus(TRUE);
     }
     elseif ($group->context == 'view') {
-      $display = EntityViewDisplay::create(array(
+      $display = EntityViewDisplay::create([
         'targetEntityType' => $group->entity_type,
         'bundle' => $group->bundle,
         'mode' => $group->mode,
-      ))->setStatus(TRUE);
+      ])->setStatus(TRUE);
     }
 
   }
 
   if (isset($display)) {
+    // Remove label from the format_settings.
+    unset($group->format_settings['label']);
+
     $data = (array) $group;
     unset($data['group_name'], $data['entity_type'], $data['bundle'], $data['mode'], $data['form'], $data['context']);
     $display->setThirdPartySetting('field_group', $group->group_name, $data);
@@ -631,7 +876,7 @@ function field_group_group_delete($group) {
     $display->save();
   }
 
-  Drupal::moduleHandler()->invokeAll('field_group_delete_field_group', array($group));
+  Drupal::moduleHandler()->invokeAll('field_group_delete_field_group', [$group]);
 }
 
 /**
@@ -650,27 +895,27 @@ function field_group_info_groups($entity_type, $bundle, $context, $mode) {
   if ($context == 'form') {
     $display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $mode);
     if (!$display) {
-      return array();
+      return [];
     }
     $data = $display->getThirdPartySettings('field_group');
   }
   if ($context == 'view') {
     $display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $mode);
     if (!$display) {
-      return array();
+      return [];
     }
     $data = $display->getThirdPartySettings('field_group');
   }
-  $groups = array();
+  $groups = [];
   if (isset($data) && is_array($data)) {
     foreach ($data as $group_name => $definition) {
-      $definition += array(
+      $definition += [
         'group_name' => $group_name,
         'entity_type' => $entity_type,
         'bundle' => $bundle,
         'context' => $context,
         'mode' => $mode,
-      );
+      ];
       $groups[$group_name] = (object) $definition;
     }
   }
@@ -701,15 +946,15 @@ function field_group_load_field_group($group_name, $entity_type, $bundle, $conte
 /**
  * Checks if a field_group exists in required context.
  *
- * @param String $group_name
+ * @param string $group_name
  *   The name of the group.
- * @param String $entity_type
+ * @param string $entity_type
  *   The name of the entity.
- * @param String $bundle
+ * @param string $bundle
  *   The bundle for the entity.
  * @param $context
  *   The context of the view mode (form or view)
- * @param String $mode
+ * @param string $mode
  *   The view mode context the group will be rendered.
  */
 function field_group_exists($group_name, $entity_type, $bundle, $context, $mode) {
@@ -719,50 +964,38 @@ function field_group_exists($group_name, $entity_type, $bundle, $context, $mode)
 /**
  * Remove empty groups on forms.
  *
- * @param String $parent_name
- *   The name of the element.
  * @param array $element
  *   The element to check the empty state.
  * @param array $groups
  *   Array of group objects.
+ * @param string $entity_type
+ *   The entity type.
  */
-function field_group_remove_empty_form_groups($name, & $element, $groups, &$form_groups, $entity) {
+function field_group_remove_empty_form_groups(&$element, $groups, $entity_type) {
+  $exceptions = ['user__account', 'comment__author'];
 
-  $exceptions = array('user__account', 'comment__author');
-
-  $children = Element::children($element);
-
-  $hasChildren = FALSE;
+  $children = Element::getVisibleChildren($element);
+  $empty_groups_indication = array_fill_keys($groups, TRUE);
   if (count($children)) {
     foreach ($children as $childname) {
-
-      if (in_array($childname, $groups)) {
-        field_group_remove_empty_form_groups($childname, $element[$childname], $groups, $form_groups, $entity);
+      $exception = $entity_type . '__' . $childname;
+      $empty_element = !(isset($element[$childname]['#type']) || isset($element[$childname]['#markup']) || in_array($exception, $exceptions));
+
+      // If the element is not empty, and it has a group. Mark the group as not
+      // empty.
+      if (!$empty_element && isset($element[$childname]['#group']) && (!isset($element[$childname]['#access']) || $element[$childname]['#access'])) {
+        $name_prefix = implode('][', $element['#array_parents']) . '][';
+        $group_name = str_replace($name_prefix, '', $element[$childname]['#group']);
+        $empty_groups_indication[$group_name] = FALSE;
       }
-      $exception = $entity . '__' . $childname;
-      $hasChildren = $hasChildren ? TRUE : (isset($element[$childname]['#type']) || isset($element[$childname]['#markup']) || in_array($exception, $exceptions));
-
     }
   }
 
-  if (!$hasChildren) {
-
-    // Remove empty elements from the #fieldgroups.
-    if (empty($element) && isset($form_groups[$name]) && !is_array($form_groups[$name])) {
-      foreach ($form_groups as $group_name => $group) {
-        if (isset($group->children)) {
-          $group_children = array_flip($group->children);
-          if (isset($group_children[$name])) {
-            unset($form_groups[$group_name]->children[$group_children[$name]]);
-          }
-        }
-      }
-    }
-
-    $element['#access'] = FALSE;
-
+  // Set access to false for all empty groups.
+  $empty_groups = array_filter($empty_groups_indication);
+  foreach (array_keys($empty_groups) as $group_name) {
+    $element[$group_name]['#access'] = FALSE;
   }
-
 }
 
 /**
diff --git a/web/modules/field_group/field_group.services.yml b/web/modules/field_group/field_group.services.yml
index b7528819ad77a3e842208a1fa71dec8905ab750f..1eafd00a992df9cbb300e0bd4afcb9001a8fa46d 100644
--- a/web/modules/field_group/field_group.services.yml
+++ b/web/modules/field_group/field_group.services.yml
@@ -10,4 +10,4 @@ services:
   field_group.param_converter:
     class: Drupal\field_group\Routing\FieldGroupConverter
     tags:
-      - { name: paramconverter }
\ No newline at end of file
+      - { name: paramconverter }
diff --git a/web/modules/field_group/formatters/accordion/accordion.js b/web/modules/field_group/formatters/accordion/accordion.js
index d4a141fb3c622fddcc652c892936d43a4c082788..a114af701e10eb3d2a92bc194ec9c929e00f1187 100644
--- a/web/modules/field_group/formatters/accordion/accordion.js
+++ b/web/modules/field_group/formatters/accordion/accordion.js
@@ -49,7 +49,7 @@
             if ($('.error', $this).length) {
               // Save first error item, for focussing it.
               if (!$firstErrorItem) {
-                $firstErrorItem = $this.parent().accordion('activate', i);
+                $firstErrorItem = $this.parent().accordion('option', 'active', i);
               }
               $('h3.ui-accordion-header').eq(i).addClass('error');
             }
diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.css b/web/modules/field_group/formatters/tabs/horizontal-tabs.css
index 088e59ed8bca38de4f2a45b1a571a5df41e0b87c..5cb6ce314fb055fc3a1dea9604ad61144e0ab476 100644
--- a/web/modules/field_group/formatters/tabs/horizontal-tabs.css
+++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.css
@@ -6,7 +6,7 @@
 }
 
 [dir="rtl"] .horizontal-tabs {
-    margin: 0 0 1em 0;
+  margin: 0 0 1em 0;
 }
 
 .horizontal-tabs .horizontal-tabs-list {
@@ -27,9 +27,10 @@
   border-left: 1px solid #dedede;
 }
 
-.horizontal-tabs-pane {
+.horizontal-tabs-panes .horizontal-tabs-pane {
   padding: 0 1em;
   border: 0;
+  background-color: unset;
 }
 
 .horizontal-tabs-pane > summary {
@@ -95,7 +96,7 @@
   display: block;
   text-decoration: none;
   padding: 0.5em 0.6em 0.3em 0.6em;
-  position:relative;
+  position: relative;
   top: 0px;
 }
 
@@ -124,6 +125,6 @@ div.field-group-htabs-wrapper .field-group-format-wrapper {
 .horizontal-tabs .horizontal-tab-hidden {
   display: block;
   position: absolute;
-  top: -100000px;
+  top: -100000000px;
   width: 100%;
 }
diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.js b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
index acf08f377ece588f47baea9c181ce00fce5b676e..363e63e4e1db92d31238c4b65b1f81e450d99a82 100644
--- a/web/modules/field_group/formatters/tabs/horizontal-tabs.js
+++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
@@ -82,8 +82,8 @@
           // If the current URL has a fragment and one of the tabs contains an
           // element that matches the URL fragment, activate that tab.
           var hash = window.location.hash.replace(/[=%;,\/]/g, '');
-          if (hash !== '#' && $(hash, this).length) {
-            tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-pane');
+          if (hash !== '#' && $(this).find(hash).length) {
+            tab_focus = $(this).find(hash).closest('.horizontal-tabs-pane');
           }
           else {
             tab_focus = $this.find('> .horizontal-tabs-pane:first');
@@ -118,8 +118,8 @@
     // Keyboard events added:
     // Pressing the Enter key will open the tab pane.
     this.link.on('keydown', function (event) {
-      event.preventDefault();
       if (event.keyCode === 13) {
+        event.preventDefault();
         self.focus();
         // Set focus on the first input field of the visible details/tab pane.
         $('.horizontal-tabs-pane :input:visible:enabled:first').trigger('focus');
diff --git a/web/modules/field_group/includes/field_ui.inc b/web/modules/field_group/includes/field_ui.inc
index 6a3cf76a58f87a2b5f5723d474542eb355435227..318dd1ef9087437f17559e55935e956f102fc726 100644
--- a/web/modules/field_group/includes/field_ui.inc
+++ b/web/modules/field_group/includes/field_ui.inc
@@ -6,9 +6,15 @@
  * needed on the Fields UI Manage forms (display and fields).
  */
 
+use Drupal\field_group\FieldgroupUi;
+use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
+use Drupal\Core\Entity\EntityDisplayBase;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Link;
 use Drupal\Core\Render\Element;
+use Drupal\field_group\FormatterHelper;
 use Drupal\field_ui\Form\EntityDisplayFormBase;
 
 /**
@@ -21,26 +27,40 @@
  *
  * @return \stdClass
  */
-function field_group_field_ui_form_params($form, \Drupal\Core\Entity\EntityDisplayBase $display) {
+function field_group_field_ui_form_params($form, EntityDisplayBase $display) {
 
   $params = new stdClass();
   $params->entity_type = $display->getTargetEntityTypeId();
   $params->bundle = $display->getTargetBundle();
-  $params->region_callback = 'field_group_display_overview_row_region';
   $params->mode = $display->getMode();
   $params->context = field_group_get_context_from_display($display);
 
-  $params->groups = array();
+  $params->groups = [];
   $params->groups = field_group_info_groups($params->entity_type, $params->bundle, $params->context, $params->mode);
 
   // Gather parenting data.
-  $params->parents = array();
+  $params->parents = [];
   foreach ($params->groups as $name => $group) {
     foreach ($group->children as $child) {
-      $params->parents[$child] = $name;
+      // Field UI js sometimes can trigger an endless loop. Check if the parent of this field is not a child.
+      if ($child !== $group->parent_name) {
+        $params->parents[$child] = $name;
+      }
     }
   }
 
+  // Get possible regions.
+  $layout_info = $display->getThirdPartySettings('field_layout');
+  if (!empty($layout_info) && isset($layout_info['id'])) {
+    $layout = \Drupal::service('plugin.manager.core.layout')->getDefinition($layout_info['id']);
+    $params->available_regions = $layout->getRegionNames();
+    $params->default_region = $layout->getDefaultRegion() ?: 'hidden';
+  }
+  else {
+    $params->available_regions = ['content', 'hidden'];
+    $params->default_region = 'hidden';
+  }
+
   return $params;
 }
 
@@ -51,11 +71,11 @@ function field_group_field_ui_form_params($form, \Drupal\Core\Entity\EntityDispl
  *
  * @return string
  */
-function field_group_get_context_from_display(\Drupal\Core\Entity\EntityDisplayBase $display) {
-  if ($display instanceof \Drupal\Core\Entity\Display\EntityFormDisplayInterface) {
+function field_group_get_context_from_display(EntityDisplayBase $display) {
+  if ($display instanceof EntityFormDisplayInterface) {
     return 'form';
   }
-  elseif ($display instanceof \Drupal\Core\Entity\Display\EntityViewDisplayInterface) {
+  elseif ($display instanceof EntityViewDisplayInterface) {
     return 'view';
   }
 
@@ -71,12 +91,12 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for
     return;
   }
 
-  $callback_object = $form_state->getBuildInfo()['callback_object'];
-  if (!$callback_object instanceof EntityDisplayFormBase) {
+  $entity_display_form = $form_state->getBuildInfo()['callback_object'];
+  if (!$entity_display_form instanceof EntityDisplayFormBase) {
     throw new InvalidArgumentException('Unkown callback object.');
   }
 
-  $display = $callback_object->getEntity();
+  $display = $entity_display_form->getEntity();
 
   $params = field_group_field_ui_form_params($form, $display);
   $form['#fieldgroups'] = array_keys($params->groups);
@@ -106,9 +126,10 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for
     }
   }
 
-  $formatter_options = field_group_field_formatter_options($params->context);
+  $formatter_options = FormatterHelper::formatterOptions($params->context);
 
   $refresh_rows = isset($form_state_values['refresh_rows']) ? $form_state_values['refresh_rows'] : (isset($form_state->getUserInput()['refresh_rows']) ? $form_state->getUserInput()['refresh_rows'] : NULL);
+
   // Create the group rows and check actions.
   foreach ($form['#fieldgroups'] as $name) {
     $group = &$field_group_form_state[$name];
@@ -134,132 +155,139 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for
     $settings = field_group_format_settings_form($group, $form, $form_state);
 
     $id = strtr($name, '_', '-');
-    $js_rows_data[$id] = array('type' => 'group', 'name' => $name);
+    $js_rows_data[$id] = ['type' => 'group', 'name' => $name];
     // A group cannot be selected as its own parent.
     $parent_options = $table['#parent_options'];
+    $region = isset($group->region) && in_array($group->region, $params->available_regions) ? $group->region : $params->default_region;
     unset($parent_options[$name]);
-    $table[$name] = array(
-      '#attributes' => array('class' => array('draggable', 'field-group'), 'id' => $id),
+    $table[$name] = [
+      '#attributes' => ['class' => ['draggable', 'field-group'], 'id' => $id],
       '#row_type' => 'group',
-      '#region_callback' => $params->region_callback,
-      '#js_settings' => array('rowHandler' => 'group'),
-      'human_name' => array(
+      '#region_callback' => 'field_group_display_overview_row_region',
+      '#js_settings' => ['rowHandler' => 'group'],
+      'human_name' => [
         '#markup' => Html::escape(t($group->label)),
         '#prefix' => '<span class="group-label">',
         '#suffix' => '</span>',
-      ),
-      'weight' => array(
+      ],
+      'weight' => [
         '#type' => 'textfield',
         '#default_value' => $group->weight,
         '#size' => 3,
-        '#attributes' => array('class' => array('field-weight')),
-      ),
-      'parent_wrapper' => array(
-        'parent' => array(
+        '#attributes' => ['class' => ['field-weight']],
+      ],
+      'parent_wrapper' => [
+        'parent' => [
           '#type' => 'select',
-          '#options' =>  $parent_options,
+          '#options' => $parent_options,
           '#empty_value' => '',
           '#default_value' => isset($params->parents[$name]) ? $params->parents[$name] : '',
-          '#attributes' => array('class' => array('field-parent')),
-          '#parents' => array('fields', $name, 'parent'),
-        ),
-        'hidden_name' => array(
+          '#attributes' => ['class' => ['field-parent']],
+          '#parents' => ['fields', $name, 'parent'],
+        ],
+        'hidden_name' => [
           '#type' => 'hidden',
           '#default_value' => $name,
-          '#attributes' => array('class' => array('field-name')),
-        ),
-      ),
-    );
+          '#attributes' => ['class' => ['field-name']],
+        ],
+      ],
+      'region' => [
+        '#type' => 'select',
+        '#options' => $entity_display_form->getRegionOptions(),
+        '#default_value' => $region,
+        '#attributes' => ['class' => ['field-region']],
+      ],
+    ];
 
     // For view settings. Add a spacer cell. We can't use colspan because of the javascript .
     if ($params->context == 'view') {
-      $table[$name] += array(
-        'spacer' => array(
-          '#markup' => '&nbsp;'
-        )
-      );
+      $table[$name] += [
+        'spacer' => [
+          '#markup' => '&nbsp;',
+        ],
+      ];
     }
 
-    $table[$name] += array(
-      'format' => array(
-        'type' => array(
+    $table[$name] += [
+      'format' => [
+        'type' => [
           '#type' => 'select',
           '#options' => $formatter_options,
           '#default_value' => $group->format_type,
-          '#attributes' => array('class' => array('field-group-type')),
-        ),
-      ),
-    );
-
-    $base_button = array(
-      '#submit' => array(
-        array($form_state->getBuildInfo()['callback_object'], 'multistepSubmit')
-      ),
-      '#ajax' => array(
-        'callback' => array($form_state->getBuildInfo()['callback_object'], 'multistepAjax'),
+          '#attributes' => ['class' => ['field-group-type']],
+        ],
+      ],
+    ];
+
+    $base_button = [
+      '#submit' => [
+        [$form_state->getBuildInfo()['callback_object'], 'multistepSubmit'],
+      ],
+      '#ajax' => [
+        'callback' => [$form_state->getBuildInfo()['callback_object'], 'multistepAjax'],
         'wrapper' => 'field-display-overview-wrapper',
         'effect' => 'fade',
-      ),
+      ],
       '#field_name' => $name,
-    );
+    ];
 
     if ($form_state->get('plugin_settings_edit') == $name) {
-      $table[$name]['format']['#cell_attributes'] = array('colspan' => 2);
-      $table[$name]['format']['format_settings'] = array(
+      $table[$name]['format']['#cell_attributes'] = ['colspan' => 2];
+      $table[$name]['format']['format_settings'] = [
         '#type' => 'container',
-        '#attributes' => array('class' => array('field-plugin-settings-edit-form')),
-        '#parents' => array('fields', $name, 'settings_edit_form'),
+        '#attributes' => ['class' => ['field-plugin-settings-edit-form']],
+        '#parents' => ['fields', $name, 'settings_edit_form'],
         '#weight' => -5,
-        'label' => array(
+        'label' => [
           '#markup' => t('Field group format:') . ' <span class="formatter-name">' . $group->format_type . '</span>',
-        ),
+        ],
         // Create a settings form where hooks can pick in.
         'settings' => $settings,
-        'actions' => array(
+        'actions' => [
           '#type' => 'actions',
-          'save_settings' => $base_button + array(
+          'save_settings' => $base_button + [
             '#type' => 'submit',
             '#name' => $name . '_plugin_settings_update',
             '#value' => t('Update'),
             '#op' => 'update',
-          ),
-          'cancel_settings' => $base_button + array(
+          ],
+          'cancel_settings' => $base_button + [
             '#type' => 'submit',
             '#name' => $name . '_plugin_settings_cancel',
             '#value' => t('Cancel'),
             '#op' => 'cancel',
             // Do not check errors for the 'Cancel' button.
-            '#limit_validation_errors' => array(),
-          ),
-        ),
-      );
+            '#limit_validation_errors' => [],
+          ],
+        ],
+      ];
       $table[$name]['#attributes']['class'][] = 'field-formatter-settings-editing';
-      $table[$name]['format']['type']['#attributes']['class'] = array('visually-hidden');
+      $table[$name]['format']['type']['#attributes']['class'] = ['visually-hidden'];
     }
     else {
       // After saving, the settings are updated here aswell. First we create
       // the element for the table cell.
-      $table[$name]['settings_summary'] = array('#markup' => '');
+      $table[$name]['settings_summary'] = ['#markup' => ''];
       if (!empty($group->format_settings)) {
         $table[$name]['settings_summary'] = field_group_format_settings_summary($name, $group);
       }
       // Add the configure button.
-      $table[$name]['settings_edit'] = $base_button + array(
+      $table[$name]['settings_edit'] = $base_button + [
         '#type' => 'image_button',
         '#name' => $name . '_group_settings_edit',
         '#src' => 'core/misc/icons/787878/cog.svg',
-        '#attributes' => array('class' => array('field-plugin-settings-edit'), 'alt' => t('Edit')),
+        '#attributes' => ['class' => ['field-plugin-settings-edit'], 'alt' => t('Edit')],
         '#op' => 'edit',
             // Do not check errors for the 'Edit' button, but make sure we get
             // the value of the 'plugin type' select.
-        '#limit_validation_errors' => array(array('fields', $name, 'type')),
+        '#limit_validation_errors' => [['fields', $name, 'type']],
         '#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
         '#suffix' => '</div>',
-      );
+      ];
 
-      $delete_route = \Drupal\field_group\FieldgroupUi::getDeleteRoute($group);
+      $delete_route = FieldgroupUi::getDeleteRoute($group);
 
-      $table[$name]['settings_edit']['#suffix'] .= Drupal::l(t('delete'), $delete_route);
+      $table[$name]['settings_edit']['#suffix'] .= Link::fromTextAndUrl(t('delete'), $delete_route)->toString();
     }
 
     $form_state->set('field_group', $field_group_form_state);
@@ -276,29 +304,29 @@ function field_group_field_ui_display_form_alter(&$form, FormStateInterface $for
   // Create the settings for fieldgroup as vertical tabs (merged with DS).
   field_group_field_ui_create_vertical_tabs($form, $form_state, $params);
 
-  // Show a warning if the user has not set up required containers
+  // Show a warning if the user has not set up required containers.
   if ($form['#fieldgroups']) {
 
-    $parent_requirements = array(
-      'accordion-item' => array(
+    $parent_requirements = [
+      'accordion-item' => [
         'parent' => 'accordion',
         'message' => 'Each Accordion item element needs to have a parent Accordion group element.',
-      ),
-    );
+      ],
+    ];
 
     // On display overview tabs need to be checked.
     if (field_group_get_context_from_display($display) == 'view') {
-      $parent_requirements['tab'] = array(
+      $parent_requirements['tab'] = [
         'parent' => 'tabs',
         'message' => 'Each tab element needs to have a parent tabs group element.',
-      );
+      ];
     }
 
     foreach ($form['#fieldgroups'] as $group_name) {
       $group_check = field_group_load_field_group($group_name, $params->entity_type, $params->bundle, $params->context, $params->mode);
       if (isset($parent_requirements[$group_check->format_type])) {
         if (!$group_check->parent_name || field_group_load_field_group($group_check->parent_name, $params->entity_type, $params->bundle, $params->context, $params->mode)->format_type != $parent_requirements[$group_check->format_type]['parent']) {
-          drupal_set_message(t($parent_requirements[$group_check->format_type]['message']), 'warning', FALSE);
+          \Drupal::messenger()->addMessage(t($parent_requirements[$group_check->format_type]['message']), 'warning', FALSE);
         }
       }
     }
@@ -313,7 +341,7 @@ function field_group_field_ui_create_vertical_tabs(&$form, &$form_state, $params
   $form_state->set('field_group_params', $params);
 
   $existing_group_config = \Drupal::configFactory()->listAll('field_group.' . $params->entity_type . '.' . $params->bundle);
-  $displays = array();
+  $displays = [];
   foreach ($existing_group_config as $config) {
     $group = \Drupal::config($config)->get();
     if ($group['context'] == $params->context && $group['mode'] == $params->mode) {
@@ -329,73 +357,82 @@ function field_group_field_ui_create_vertical_tabs(&$form, &$form_state, $params
 
   // Add additional settings vertical tab.
   if (!isset($form['additional_settings'])) {
-    $form['additional_settings'] = array(
+    $form['additional_settings'] = [
       '#type' => 'vertical_tabs',
-      '#theme_wrappers' => array('vertical_tabs'),
+      '#theme_wrappers' => ['vertical_tabs'],
       '#prefix' => '<div>',
       '#suffix' => '</div>',
       '#tree' => TRUE,
-    );
+    ];
   }
 
   // Add extra guidelines for webmaster.
-  $form['field_group'] = array(
+  $form['field_group'] = [
     '#type' => 'details',
     '#group' => 'additional_settings',
     '#title' => t('Fieldgroups'),
     '#description' => t('<p class="fieldgroup-help">Fields can be dragged into groups with unlimited nesting. Each fieldgroup format comes with a configuration form, specific for that format type.<br />Note that some formats come in pair. These types have a html wrapper to nest its fieldgroup children. E.g. Place accordion items into the accordion, vertical tabs in vertical tab group and horizontal tabs in the horizontal tab group. There is one exception to this rule, you can use a vertical tab without a wrapper when the additional settings tabs are available. E.g. node forms.</p>'),
     '#collapsible' => TRUE,
     '#open' => TRUE,
-  );
-  $form['field_group']['fieldgroup_clone'] = array(
+  ];
+  $form['field_group']['fieldgroup_clone'] = [
     '#title' => t('Select source display'),
     '#description' => t('Clone fieldgroups from selected display to the current display'),
     '#type' => 'select',
     '#options' => $displays,
-    '#default_value' => 'none'
-  );
-  $form['field_group']['fieldgroup_submit'] = array(
+    '#default_value' => 'none',
+  ];
+  $form['field_group']['fieldgroup_submit'] = [
     '#type' => 'submit',
     '#value' => t('Clone'),
-    '#validate' => array('field_group_field_ui_clone_field_groups_validate'),
-    '#submit' => array('field_group_field_ui_clone_field_groups')
-  );
+    '#validate' => ['field_group_field_ui_clone_field_groups_validate'],
+    '#submit' => ['field_group_field_ui_clone_field_groups'],
+  ];
 
 }
 
 /**
  * Returns the region to which a row in the 'Manage display' screen belongs.
- * @param Array $row A field or field_group row
+ *
+ * @param array $row
+ *   A field or field_group row.
+ *
  * @return String the current region.
  */
 function field_group_display_overview_row_region($row) {
-  switch ($row['#row_type']) {
-    case 'group':
-      return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'content');
-  }
+  // We already cleaned region when building the form.
+  return $row['region']['#value'];
 }
 
 /**
  * Submit handler for the overview screens.
- * @param Array $form The complete form.
- * @param FormStateInterface $form_state The state of the form.
+ *
+ * @param array $form
+ *   The complete form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The state of the form.
  */
 function field_group_field_overview_submit($form, FormStateInterface $form_state) {
   $form_values = $form_state->getValue('fields');
-  $fields_added = $form_state->getValue('fields_added');
 
   /**
    * @var \Drupal\Core\Entity\EntityDisplayBase $display
    */
   $display = $form['#context'];
+  $manager = Drupal::service('plugin.manager.field_group.formatters');
 
   $entity_type = $display->get('targetEntityType');
   $bundle = $display->get('bundle');
   $mode = $display->get('mode');
   $context = field_group_get_context_from_display($display);
 
+  // Load field layout info.
+  $field_group_params = $form_state->get('field_group_params');
+  $layout_regions = $field_group_params->available_regions;
+  $default_region = $field_group_params->default_region;
+
   // Collect children.
-  $children = array_fill_keys($form['#fieldgroups'], array());
+  $children = array_fill_keys($form['#fieldgroups'], []);
   foreach ($form_values as $name => $value) {
     if (!empty($value['parent'])) {
       $children[$value['parent']][$name] = $name;
@@ -403,7 +440,7 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state
   }
 
   // Update existing groups.
-  $groups = field_group_info_groups($entity_type, $bundle, $context, $mode, TRUE);
+  $groups = field_group_info_groups($entity_type, $bundle, $context, $mode);
   $field_group_form_state = $form_state->get('field_group');
   if (!empty($field_group_form_state)) {
     foreach ($form['#fieldgroups'] as $group_name) {
@@ -415,10 +452,17 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state
 
       $group = $groups[$group_name];
       $group->label = $field_group_form_state[$group_name]->label;
+
+      // Sometimes field UI does a fuckup if people drag to fast when switching nested values.
+      // This results in an endless loop => Cleanup before saving.
+      // unset($children[$group_name][$form_values[$group_name]['parent']]);.
       $group->children = array_keys($children[$group_name]);
       $group->parent_name = $form_values[$group_name]['parent'];
       $group->weight = $form_values[$group_name]['weight'];
 
+      // If region is changed, make sure the group ends up in an existing region.
+      $group->region = !in_array($form_values[$group_name]['region'], $layout_regions) ? $default_region : $form_values[$group_name]['region'];
+
       $old_format_type = $group->format_type;
       $group->format_type = isset($form_values[$group_name]['format']['type']) ? $form_values[$group_name]['format']['type'] : 'visible';
       if (isset($field_group_form_state[$group_name]->format_settings)) {
@@ -427,8 +471,7 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state
 
       // If the format type is changed, make sure we have all required format settings.
       if ($group->format_type != $old_format_type) {
-        $default_formatter_settings = _field_group_get_default_formatter_settings($group->format_type, $context);
-        $group->format_settings += $default_formatter_settings;
+        $group->format_settings += $manager->getDefaultSettings($group->format_type, $context);
       }
 
       /** @var EntityFormInterface $entity_form */
@@ -446,27 +489,37 @@ function field_group_field_overview_submit($form, FormStateInterface $form_state
 
 /**
  * Creates a form for field_group formatters.
- * @param Object $group The FieldGroup object.
+ *
+ * @param Object $group
+ *   The FieldGroup object.
  */
 function field_group_format_settings_form(&$group, $form, $form_state) {
   $manager = \Drupal::service('plugin.manager.field_group.formatters');
-  $plugin = $manager->getInstance(array(
+  $plugin = $manager->getInstance([
     'format_type' => $group->format_type,
-    'configuration' => array('label' => $group->label, 'settings' => $group->format_settings),
+    'configuration' => [
+      'label' => $group->label,
+      'settings' => $group->format_settings,
+    ],
     'group' => $group,
-  ));
+  ]);
+
+  if ($plugin) {
+    return $plugin->settingsForm($form, $form_state);
+  }
 
-  return $plugin->settingsForm($form, $form_state);
+  return [];
 }
 
 /**
  * Update the row so that the group variables are updated.
  * The rendering of the elements needs the updated defaults.
+ *
  * @param Object $group
  * @param array $settings
  */
 function field_group_formatter_row_update(& $group, $settings) {
-  // if the row has changed formatter type, update the group object
+  // If the row has changed formatter type, update the group object.
   if (!empty($settings['format']['type']) && $settings['format']['type'] != $group->format_type) {
     $group->format_type = $settings['format']['type'];
     field_group_formatter_settings_update($group, $settings);
@@ -475,14 +528,17 @@ function field_group_formatter_row_update(& $group, $settings) {
 
 /**
  * Update handler for field_group configuration settings.
- * @param Object $group The group object
- * @param Array $settings Configuration settings
+ *
+ * @param Object $group
+ *   The group object.
+ * @param array $settings
+ *   Configuration settings.
  */
 function field_group_formatter_settings_update(& $group, $settings) {
 
-  // for format changes we load the defaults.
+  // For format changes we load the defaults.
   if (empty($settings['settings_edit_form']['settings'])) {
-    $group->format_settings = _field_group_get_default_formatter_settings($group->format_type, $group->context);
+    $group->format_settings = Drupal::service('plugin.manager.field_group.formatters')->getDefaultSettings($group->format_type, $group->context);
   }
   else {
     $group->format_type = $settings['format']['type'];
@@ -493,25 +549,37 @@ function field_group_formatter_settings_update(& $group, $settings) {
 
 /**
  * Creates a summary for the field format configuration summary.
- * @param String $group_name The name of the group
- * @param Object $group The group object
+ *
+ * @param string $group_name
+ *   The name of the group.
+ * @param Object $group
+ *   The group object.
+ *
  * @return Array ready to be rendered.
  */
 function field_group_format_settings_summary($group_name, $group) {
 
   $manager = \Drupal::service('plugin.manager.field_group.formatters');
-  $plugin = $manager->getInstance(array(
+  $plugin = $manager->getInstance([
     'format_type' => $group->format_type,
-    'configuration' => array('label' => $group->label, 'settings' => $group->format_settings),
+    'configuration' => [
+      'label' => $group->label,
+      'settings' => $group->format_settings,
+    ],
     'group' => $group,
-  ));
+  ]);
 
-  $summary = $plugin->settingsSummary();
+  if ($plugin) {
+    $summary = $plugin->settingsSummary();
+  }
+  else {
+    $summary = '';
+  }
 
-  return array(
+  return [
     '#markup' => '<div class="field-plugin-summary">' . implode('<br />', $summary) . '</div>',
-    '#cell_attributes' => array('class' => array('field-plugin-summary-cell')),
-  );
+    '#cell_attributes' => ['class' => ['field-plugin-summary-cell']],
+  ];
 }
 
 /**
@@ -536,7 +604,7 @@ function field_group_field_ui_clone_field_groups_validate($form, FormStateInterf
   foreach ($source_groups as $key => $group) {
     if (in_array($group->format_type, $non_existing_types)) {
       unset($source_groups[$key]);
-      drupal_set_message(t('Skipping @group because this type does not exist in current mode', array('@group' => $group->label)), 'warning');
+      \Drupal::messenger()->addMessage(t('Skipping @group because this type does not exist in current mode', ['@group' => $group->label]), 'warning');
     }
   }
 
@@ -562,16 +630,16 @@ function field_group_field_ui_clone_field_groups($form, FormStateInterface $form
     $field_group_params = $form_state->get('field_group_params');
     foreach ($source_groups as $source_group) {
       if (in_array($source_group->group_name, $fields)) {
-        drupal_set_message(t('Fieldgroup @group is not cloned since a group already exists with the same name.', array('@group' => $source_group->group_name)), 'warning');
+        \Drupal::messenger()->addMessage(t('Fieldgroup @group is not cloned since a group already exists with the same name.', ['@group' => $source_group->group_name]), 'warning');
         continue;
       }
 
       $source_group->context = $field_group_params->context;
       $source_group->mode = $field_group_params->mode;
-      $source_group->children = array();
+      $source_group->children = [];
       field_group_group_save($source_group);
 
-      drupal_set_message(t('Fieldgroup @group cloned successfully.', array('@group' => $source_group->group_name)));
+      \Drupal::messenger()->addMessage(t('Fieldgroup @group cloned successfully.', ['@group' => $source_group->group_name]));
 
     }
   }
diff --git a/web/modules/field_group/includes/helpers.inc b/web/modules/field_group/includes/helpers.inc
deleted file mode 100644
index a6735f094d99d292df70acb218fd976d6766ae83..0000000000000000000000000000000000000000
--- a/web/modules/field_group/includes/helpers.inc
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-use Drupal\Core\Form\FormStateInterface;
-
-/*
- * @file
- * Helper functions for the fieldgroup module.
- */
-
-/**
- * Get the default formatter settings for a given formatter and context.
- */
-function _field_group_get_default_formatter_settings($format_type, $context) {
-  $manager = Drupal::service('plugin.manager.field_group.formatters');
-  return $manager->getDefaultSettings($format_type, $context);
-}
-
-/**
- * Return an array of field_group_formatter options.
- */
-function field_group_field_formatter_options($type) {
-  $options = &drupal_static(__FUNCTION__);
-
-  if (!isset($options)) {
-    $options = array();
-
-    $manager = Drupal::service('plugin.manager.field_group.formatters');
-    $formatters = $manager->getDefinitions();
-
-    foreach ($formatters as $formatter) {
-      if (in_array($type, $formatter['supported_contexts'])) {
-        $options[$formatter['id']] = $formatter['label'];
-      }
-    }
-  }
-
-  return $options;
-}
-
-/**
- * Validate the entered css class from the submitted format settings.
- * @param Array $element The validated element
- * @param FormStateInterface $form_state The state of the form.
- */
-function field_group_validate_css_class($element, FormStateInterface $form_state) {
-  $form_state_values = $form_state->getValues();
-  $plugin_name = $form_state->get('plugin_settings_edit');
-  if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes']) && !preg_match('!^[A-Za-z0-9-_ ]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes'])) {
-    $form_state->setError($element, $form_state, t('The css class must include only letters, numbers, underscores and dashes.'));
-  }
-}
-
-/**
- * Validate the entered id attribute from the submitted format settings.
- * @param Array $element The validated element
- * @param FormStateInterface $form_state The state of the form.
- */
-function field_group_validate_id($element, FormStateInterface $form_state) {
-  $form_state_values = $form_state->getValues();
-  $plugin_name = $form_state->get('plugin_settings_edit');
-  if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id']) && !preg_match('!^[A-Za-z0-9-_]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id'])) {
-    Drupal::formBuilder()->setError($element, $form_state, t('The id must include only letters, numbers, underscores and dashes.'));
-  }
-}
\ No newline at end of file
diff --git a/web/modules/field_group/js/field_group.field_ui.js b/web/modules/field_group/js/field_group.field_ui.js
index b23a51235d09d7db2fef8c0aecf301ea4e1ee4a6..7aba6df1c62dccbb46ee78be1e79bb3f15cb9a1f 100644
--- a/web/modules/field_group/js/field_group.field_ui.js
+++ b/web/modules/field_group/js/field_group.field_ui.js
@@ -68,15 +68,15 @@
     this.tableDrag = data.tableDrag;
 
     // Attach change listener to the 'group format' select.
-    this.$formatSelect = $('select.field-group-type', row);
-    this.$formatSelect.change(Drupal.fieldUIOverview.onChange);
+    this.$regionSelect = $(row).find('select.field-region');
+    this.$regionSelect.on('change', Drupal.fieldUIOverview.onChange);
 
     return this;
   };
 
   Drupal.fieldUIDisplayOverview.group.prototype = {
-    getRegion: function () {
-      return (this.$formatSelect.val() === 'hidden') ? 'hidden' : 'content';
+    getRegion: function getRegion() {
+      return this.$regionSelect.val();
     },
 
     regionChange: function (region, recurse) {
@@ -84,28 +84,13 @@
       // Default recurse to true.
       recurse = (typeof recurse === 'undefined') || recurse;
 
-      // When triggered by a row drag, the 'format' select needs to be adjusted to
+      // When triggered by a row drag, the 'region' select needs to be adjusted to
       // the new region.
-      var currentValue = this.$formatSelect.val();
-      var value;
-      switch (region) {
-        case 'visible':
-          if (currentValue === 'hidden') {
-            // Restore the group format back to 'fieldset'.
-            value = 'fieldset';
-          }
-          break;
-
-        default:
-          value = 'hidden';
-          break;
-      }
-      if (typeof value !== 'undefined') {
-        this.$formatSelect.val(value);
-      }
+      region = region.replace(/-/g, '_');
+      this.$regionSelect.val(region);
 
       var refreshRows = {};
-      refreshRows[this.name] = this.$formatSelect.get(0);
+      refreshRows[this.name] = this.$regionSelect.get(0);
 
       if (recurse) {
         this.regionChangeFields(region, this, refreshRows);
diff --git a/web/modules/field_group/src/Annotation/FieldGroupFormatter.php b/web/modules/field_group/src/Annotation/FieldGroupFormatter.php
index 0e3752d8a94a6088523d1f89fd0eee652fb7b2d0..d7acb983dd38f4ed679399504f1c6106da465919 100644
--- a/web/modules/field_group/src/Annotation/FieldGroupFormatter.php
+++ b/web/modules/field_group/src/Annotation/FieldGroupFormatter.php
@@ -31,20 +31,11 @@ class FieldGroupFormatter extends Plugin {
   /**
    * The human-readable name of the formatter type.
    *
-   * @ingroup plugin_translatable
-   *
    * @var \Drupal\Core\Annotation\Translation
-   */
-  public $label;
-
-  /**
-   * A short description of the formatter type.
    *
    * @ingroup plugin_translatable
-   *
-   * @var \Drupal\Core\Annotation\Translation
    */
-  public $description;
+  public $label;
 
   /**
    * The name of the fieldgroup formatter class.
@@ -60,20 +51,20 @@ class FieldGroupFormatter extends Plugin {
    *
    * @var array
    */
-  public $supported_contexts = array();
+  public $supported_contexts = [];
 
   /**
    * The different format types available for this formatter.
    *
    * @var array
    */
-  public $format_types = array();
+  public $format_types = [];
 
   /**
    * An integer to determine the weight of this formatter relative to other
    * formatter in the Field UI when selecting a formatter for a given group.
    *
-   * @var int optional
+   * @var int
    */
   public $weight = NULL;
 
diff --git a/web/modules/field_group/src/Element/Accordion.php b/web/modules/field_group/src/Element/Accordion.php
index 3addbebcaef144d678c3e87cea6863ef0371f693..72ba8e608fd3596118cd0cd677ba74cf66c91a2c 100644
--- a/web/modules/field_group/src/Element/Accordion.php
+++ b/web/modules/field_group/src/Element/Accordion.php
@@ -18,12 +18,16 @@ class Accordion extends RenderElement {
   public function getInfo() {
     $class = get_class($this);
 
-    return array(
-      '#process' => array(
-        array($class, 'processAccordion'),
-      ),
-      '#theme_wrappers' => array('field_group_accordion'),
-    );
+    return [
+      '#process' => [
+        [$class, 'processGroup'],
+        [$class, 'processAccordion'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderGroup'],
+      ],
+      '#theme_wrappers' => ['field_group_accordion'],
+    ];
   }
 
   /**
@@ -38,15 +42,16 @@ public function getInfo() {
    * @return array
    *   The processed element.
    */
-  public static function processAccordion(&$element, FormStateInterface $form_state) {
+  public static function processAccordion(array &$element, FormStateInterface $form_state) {
 
     // Add the jQuery UI accordion.
     $element['#attached']['library'][] = 'field_group/formatter.accordion';
+    $element['#attached']['library'][] = 'field_group/core';
 
     // Add the effect class.
     if (isset($element['#effect'])) {
       if (!isset($element['#attributes']['class'])) {
-        $element['#attributes']['class'] = array();
+        $element['#attributes']['class'] = [];
       }
       $element['#attributes']['class'][] = 'effect-' . $element['#effect'];
     }
diff --git a/web/modules/field_group/src/Element/AccordionItem.php b/web/modules/field_group/src/Element/AccordionItem.php
index 8d6dfe458013df5065d26267abbbf7aad7b14992..dbfd913630ded482a4cf6b9eec2aa7f7a8cd35c2 100644
--- a/web/modules/field_group/src/Element/AccordionItem.php
+++ b/web/modules/field_group/src/Element/AccordionItem.php
@@ -15,10 +15,18 @@ class AccordionItem extends RenderElement {
    * {@inheritdoc}
    */
   public function getInfo() {
-    return array(
-      '#open' => TRUE,
-      '#theme_wrappers' => array('field_group_accordion_item'),
-    );
+    $class = get_class($this);
+
+    return [
+      '#process' => [
+        [$class, 'processGroup'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderGroup'],
+      ],
+      '#open' => FALSE,
+      '#theme_wrappers' => ['field_group_accordion_item'],
+    ];
   }
 
 }
diff --git a/web/modules/field_group/src/Element/HorizontalTabs.php b/web/modules/field_group/src/Element/HorizontalTabs.php
index f1ee96fe03e3ef682afdeb59549d8b5b63d6eb8f..dab221c9226d911371268f7bf45db4d5cf5fa2a8 100644
--- a/web/modules/field_group/src/Element/HorizontalTabs.php
+++ b/web/modules/field_group/src/Element/HorizontalTabs.php
@@ -3,6 +3,7 @@
 namespace Drupal\field_group\Element;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
 use Drupal\Core\Render\Element\RenderElement;
 
 /**
@@ -21,13 +22,57 @@ class HorizontalTabs extends RenderElement {
   public function getInfo() {
     $class = get_class($this);
 
-    return array(
+    return [
       '#default_tab' => '',
-      '#process' => array(
-        array($class, 'processHorizontalTabs'),
-      ),
-      '#theme_wrappers' => array('horizontal_tabs'),
-    );
+      '#process' => [
+        [$class, 'processHorizontalTabs'],
+        [$class, 'processGroup'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderGroup'],
+      ],
+      '#theme_wrappers' => ['horizontal_tabs'],
+    ];
+  }
+
+  /**
+   * Pre render the group to support #group parameter.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element.
+   *
+   * @return array
+   *   The modified element with all group members.
+   */
+  public static function preRenderGroup($element) {
+    // The element may be rendered outside of a Form API context.
+    if (!isset($element['#parents']) || !isset($element['#groups'])) {
+      return $element;
+    }
+
+    if (isset($element['#group'])) {
+      // Contains form element summary functionalities.
+      $element['#attached']['library'][] = 'core/drupal.form';
+
+      $group = $element['#group'];
+      // If this element belongs to a group, but the group-holding element does
+      // not exist, we need to render it (at its original location).
+      if (!isset($element['#groups'][$group]['#group_exists'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // If we injected this element into the group, then we want to render it.
+      elseif (!empty($element['#group_details'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // Otherwise, this element belongs to a group and the group exists, so we do
+      // not render it.
+      elseif (Element::children($element['#groups'][$group])) {
+        $element['#printed'] = TRUE;
+      }
+    }
+
+    return $element;
   }
 
   /**
@@ -44,15 +89,15 @@ public function getInfo() {
    * @return array
    *   The processed element.
    */
-  public static function processHorizontalTabs(&$element, FormStateInterface $form_state, $on_form = TRUE) {
+  public static function processHorizontalTabs(array &$element, FormStateInterface $form_state, $on_form = TRUE) {
 
     // Inject a new details as child, so that form_process_details() processes
     // this details element like any other details.
-    $element['group'] = array(
+    $element['group'] = [
       '#type' => 'details',
-      '#theme_wrappers' => array(),
+      '#theme_wrappers' => [],
       '#parents' => $element['#parents'],
-    );
+    ];
 
     // Add an invisible label for accessibility.
     if (!isset($element['#title'])) {
@@ -68,19 +113,66 @@ public static function processHorizontalTabs(&$element, FormStateInterface $form
       $element['#attached']['library'][] = 'core/drupal.form';
     }
 
+    $name = implode('__', $element['#parents']);
+    if ($form_state->hasValue($name . '__active_tab')) {
+      $element['#default_tab'] = $form_state->getValue($name . '__active_tab');
+    }
+
+    $groups = &$form_state->getGroups();
+    $group_name = $element['#group_name'];
+    $displayed_tab = isset($element['#default_tab']) ? $element['#default_tab'] : '';
+    if (isset($groups[$group_name]) && empty($displayed_tab)) {
+      foreach (Element::children($groups[$group_name]) as $child) {
+        $child_group = $groups[$group_name][$child];
+        if (!empty($child_group['#open']) || empty($displayed_tab)) {
+          // Use the last open group or the first group if none are open.
+          $displayed_tab = $child_group['#id'];
+        }
+      }
+    }
+
     // The JavaScript stores the currently selected tab in this hidden
     // field so that the active tab can be restored the next time the
     // form is rendered, e.g. on preview pages or when form validation
     // fails.
-    $name = implode('__', $element['#parents']);
-    if ($form_state->hasValue($name . '__active_tab')){
-      $element['#default_tab'] = $form_state->getValue($name . '__active_tab');
-    }
-    $element[$name . '__active_tab'] = array(
+    $element['#default_tab'] = $displayed_tab;
+    $element[$name . '__active_tab'] = [
       '#type' => 'hidden',
       '#default_value' => $element['#default_tab'],
-      '#attributes' => array('class' => array('horizontal-tabs-active-tab')),
-    );
+      '#attributes' => ['class' => ['horizontal-tabs-active-tab']],
+    ];
+
+    return $element;
+  }
+
+  /**
+   * Arranges elements into groups.
+   *
+   * This method is useful for non-input elements that can be used in and
+   * outside the context of a form.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element. Note that $element must be taken by reference here, so processed
+   *   child elements are taken over into $form_state.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   *
+   * @return array
+   *   The processed element.
+   */
+  public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) {
+
+    $groups = &$form_state->getGroups();
+    $element['#groups'] = &$groups;
+
+    if (isset($element['#group'])) {
+      // Add this element to the defined group (by reference).
+      $group = $element['#group'];
+      $groups[$group][] = &$element;
+    }
 
     return $element;
   }
diff --git a/web/modules/field_group/src/Element/HtmlElement.php b/web/modules/field_group/src/Element/HtmlElement.php
index e58d6e1150b32df523e185ba4dde00cbddc234cd..cdb78c5bff1701f2ec817bb144be08869e28e23a 100644
--- a/web/modules/field_group/src/Element/HtmlElement.php
+++ b/web/modules/field_group/src/Element/HtmlElement.php
@@ -18,27 +18,31 @@ class HtmlElement extends RenderElement {
   public function getInfo() {
     $class = get_class($this);
 
-    return array(
-      '#process' => array(
-        array($class, 'processHtmlElement'),
-      ),
-      '#theme_wrappers' => array('field_group_html_element'),
-    );
+    return [
+      '#process' => [
+        [$class, 'processGroup'],
+        [$class, 'processHtmlElement'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderGroup'],
+      ],
+      '#theme_wrappers' => ['field_group_html_element'],
+    ];
   }
 
   /**
-   * Process a html element
+   * Process a html element.
    *
    * @param array $element
    *   An associative array containing the properties and children of the
    *   details element.
-   * @param FormStateInterface $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
    *
    * @return array
    *   The processed element.
    */
-  public static function processHtmlElement(&$element, FormStateInterface $form_state) {
+  public static function processHtmlElement(array &$element, FormStateInterface $form_state) {
 
     // If an effect is set, we need to load extra js.
     if (!empty($element['#effect']) && $element['#effect'] !== 'none') {
diff --git a/web/modules/field_group/src/Element/VerticalTabs.php b/web/modules/field_group/src/Element/VerticalTabs.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b56bf4694fe47ce88ee11ae9069f94dd93dae03
--- /dev/null
+++ b/web/modules/field_group/src/Element/VerticalTabs.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Drupal\field_group\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+/**
+ * Provides extra processing and pre rendering on the vertical tabs.
+ */
+class VerticalTabs {
+
+  /**
+   * Pre render the group to support #group parameter.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element.
+   *
+   * @return array
+   *   The modified element with all group members.
+   */
+  public static function preRenderGroup($element) {
+    // The element may be rendered outside of a Form API context.
+    if (!isset($element['#parents']) || !isset($element['#groups'])) {
+      return $element;
+    }
+
+    if (isset($element['#group'])) {
+      // Contains form element summary functionalities.
+      $element['#attached']['library'][] = 'core/drupal.form';
+
+      $group = $element['#group'];
+      // If this element belongs to a group, but the group-holding element does
+      // not exist, we need to render it (at its original location).
+      if (!isset($element['#groups'][$group]['#group_exists'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // If we injected this element into the group, then we want to render it.
+      elseif (!empty($element['#group_details'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // Otherwise, this element belongs to a group and the group exists, so we do
+      // not render it.
+      elseif (Element::children($element['#groups'][$group])) {
+        $element['#printed'] = TRUE;
+      }
+    }
+
+    return $element;
+  }
+
+  /**
+   * Arranges elements into groups.
+   *
+   * This method is useful for non-input elements that can be used in and
+   * outside the context of a form.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element. Note that $element must be taken by reference here, so processed
+   *   child elements are taken over into $form_state.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   *
+   * @return array
+   *   The processed element.
+   */
+  public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) {
+
+    $groups = &$form_state->getGroups();
+    $element['#groups'] = &$groups;
+
+    if (isset($element['#group'])) {
+      // Add this element to the defined group (by reference).
+      $group = $element['#group'];
+      $groups[$group][] = &$element;
+    }
+
+    return $element;
+  }
+
+}
diff --git a/web/modules/field_group/src/FieldGroupFormatterBase.php b/web/modules/field_group/src/FieldGroupFormatterBase.php
index b9028c9b86b0f537edec2a344ed8a2ed9e44b484..0230b9ac3b08069f92287b7554a28717dccb98aa 100644
--- a/web/modules/field_group/src/FieldGroupFormatterBase.php
+++ b/web/modules/field_group/src/FieldGroupFormatterBase.php
@@ -3,6 +3,7 @@
 namespace Drupal\field_group;
 
 use Drupal\Core\Field\PluginSettingsBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base class for 'Fieldgroup formatter' plugin implementations.
@@ -13,7 +14,8 @@ abstract class FieldGroupFormatterBase extends PluginSettingsBase implements Fie
 
   /**
    * The group this formatter needs to render.
-   * @var stdClass
+   *
+   * @var object
    */
   protected $group;
 
@@ -52,15 +54,15 @@ abstract class FieldGroupFormatterBase extends PluginSettingsBase implements Fie
    *   The plugin_id for the formatter.
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
-   * @param $group
+   * @param \stdClass $group
    *   The group object.
    * @param array $settings
    *   The formatter settings.
    * @param string $label
    *   The formatter label.
    */
-  public function __construct($plugin_id, $plugin_definition, $group, array $settings, $label) {
-    parent::__construct(array(), $plugin_id, $plugin_definition);
+  public function __construct($plugin_id, $plugin_definition, \stdClass $group, array $settings, $label) {
+    parent::__construct([], $plugin_id, $plugin_definition);
 
     $this->group = $group;
     $this->settings = $settings;
@@ -70,7 +72,9 @@ public function __construct($plugin_id, $plugin_definition, $group, array $setti
 
   /**
    * Get the current label.
+   *
    * @return string
+   *   The current label.
    */
   public function getLabel() {
     return $this->label;
@@ -81,29 +85,31 @@ public function getLabel() {
    */
   public function settingsForm() {
 
-    $form = array();
-    $form['label'] = array(
+    $class = get_class($this);
+
+    $form = [];
+    $form['label'] = [
       '#type' => 'textfield',
       '#title' => t('Field group label'),
       '#default_value' => $this->label,
       '#weight' => -5,
-    );
+    ];
 
-    $form['id'] = array(
+    $form['id'] = [
       '#title' => t('ID'),
       '#type' => 'textfield',
       '#default_value' => $this->getSetting('id'),
       '#weight' => 10,
-      '#element_validate' => array('field_group_validate_id'),
-    );
+      '#element_validate' => [[$class, 'validateId']],
+    ];
 
-    $form['classes'] = array(
+    $form['classes'] = [
       '#title' => t('Extra CSS classes'),
       '#type' => 'textfield',
       '#default_value' => $this->getSetting('classes'),
       '#weight' => 11,
-      '#element_validate' => array('field_group_validate_css_class'),
-    );
+      '#element_validate' => [[$class, 'validateCssClass']],
+    ];
 
     return $form;
 
@@ -114,18 +120,18 @@ public function settingsForm() {
    */
   public function settingsSummary() {
 
-    $summary = array();
+    $summary = [];
 
     if ($this->getSetting('formatter')) {
       $summary[] = $this->pluginDefinition['label'] . ': ' . $this->getSetting('formatter');
     }
 
     if ($this->getSetting('id')) {
-      $summary[] = $this->t('Id: @id', array('@id' => $this->getSetting('id')));
+      $summary[] = $this->t('Id: @id', ['@id' => $this->getSetting('id')]);
     }
 
     if ($this->getSetting('classes')) {
-      $summary[] = \Drupal::translation()->translate('Extra CSS classes: @classes', array('@classes' => $this->getSetting('classes')));
+      $summary[] = \Drupal::translation()->translate('Extra CSS classes: @classes', ['@classes' => $this->getSetting('classes')]);
     }
 
     return $summary;
@@ -142,10 +148,10 @@ public static function defaultSettings() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    return array(
+    return [
       'classes' => '',
       'id' => '',
-    );
+    ];
   }
 
   /**
@@ -153,7 +159,7 @@ public static function defaultContextSettings($context) {
    */
   protected function getClasses() {
 
-    $classes = array();
+    $classes = [];
     // Add a required-fields class to trigger the js.
     if ($this->getSetting('required_fields')) {
       $classes[] = 'required-fields';
@@ -176,4 +182,49 @@ public function preRender(&$element, $rendering_object) {
     $element['#bundle'] = $this->group->bundle;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function process(&$element, $processed_object) {
+
+    $element['#group_name'] = $this->group->group_name;
+    $element['#entity_type'] = $this->group->entity_type;
+    $element['#bundle'] = $this->group->bundle;
+
+    // BC: Call the pre render layer to not break contrib plugins.
+    return $this->preRender($element, $processed_object);
+  }
+
+  /**
+   * Validate the entered css class from the submitted format settings.
+   *
+   * @param array $element
+   *   The validated element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The state of the form.
+   */
+  public static function validateCssClass(array $element, FormStateInterface $form_state) {
+    $form_state_values = $form_state->getValues();
+    $plugin_name = $form_state->get('plugin_settings_edit');
+    if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes']) && !preg_match('!^[A-Za-z0-9-_ ]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['classes'])) {
+      $form_state->setError($element, t('The css class must include only letters, numbers, underscores and dashes.'));
+    }
+  }
+
+  /**
+   * Validate the entered id attribute from the submitted format settings.
+   *
+   * @param array $element
+   *   The validated element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The state of the form.
+   */
+  public static function validateId(array $element, FormStateInterface $form_state) {
+    $form_state_values = $form_state->getValues();
+    $plugin_name = $form_state->get('plugin_settings_edit');
+    if (!empty($form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id']) && !preg_match('!^[A-Za-z0-9-_]+$!', $form_state_values['fields'][$plugin_name]['settings_edit_form']['settings']['id'])) {
+      $form_state->setError($element, t('The id must include only letters, numbers, underscores and dashes.'));
+    }
+  }
+
 }
diff --git a/web/modules/field_group/src/FieldGroupFormatterInterface.php b/web/modules/field_group/src/FieldGroupFormatterInterface.php
index 538e8007b8ec579bb46b526a3ba641de2c7afa8d..fc9dc82c48aa6ab795d32d58ee3dabea5e8849f1 100644
--- a/web/modules/field_group/src/FieldGroupFormatterInterface.php
+++ b/web/modules/field_group/src/FieldGroupFormatterInterface.php
@@ -11,6 +11,18 @@
  */
 interface FieldGroupFormatterInterface extends PluginInspectionInterface {
 
+  /**
+   * Allows the field group formatter to manipulate the field group array and attach the formatters elements.
+   * The process method is called in the #process part of theme layer, and is currently used for forms.
+   * The preRender method is called in the #pre_render part of the theme layer, and is currently used for entity displays.
+   *
+   * @param array $element
+   *   The field group render array.
+   * @param object $processed_object
+   *   The object / entity beïng processed.
+   */
+  public function process(&$element, $processed_object);
+
   /**
    * Allows the field group formatter to manipulate the field group array and attach the formatters rendering element.
    *
@@ -39,7 +51,7 @@ public function settingsForm();
    * If an empty result is returned, a UI can still be provided to display
    * a settings form in case the formatter has configurable settings.
    *
-   * @return array()
+   * @return array
    *   A short summary of the formatter settings.
    */
   public function settingsSummary();
diff --git a/web/modules/field_group/src/FieldGroupFormatterPluginManager.php b/web/modules/field_group/src/FieldGroupFormatterPluginManager.php
index 939bc3000ab1c5354c63f7421454f46c72dc2d9f..f93afbe1683893f3319ee1a0c440e188e4b760d6 100644
--- a/web/modules/field_group/src/FieldGroupFormatterPluginManager.php
+++ b/web/modules/field_group/src/FieldGroupFormatterPluginManager.php
@@ -20,8 +20,6 @@ class FieldGroupFormatterPluginManager extends DefaultPluginManager {
    *   keyed by the corresponding namespace to look for plugin implementations.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
    *   Cache backend instance to use.
-   * @param \Drupal\Core\Language\LanguageManager $language_manager
-   *   The language manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
    */
@@ -35,7 +33,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
   /**
    * {@inheritdoc}
    */
-  public function createInstance($plugin_id, array $configuration = array()) {
+  public function createInstance($plugin_id, array $configuration = []) {
     $plugin_definition = $this->getDefinition($plugin_id);
     $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition);
 
@@ -86,9 +84,9 @@ public function getInstance(array $options) {
       return NULL;
     }
 
-    $configuration += array(
+    $configuration += [
       'group' => $options['group'],
-    );
+    ];
 
     return $this->createInstance($plugin_id, $configuration);
   }
@@ -97,21 +95,20 @@ public function getInstance(array $options) {
    * Merges default values for formatter configuration.
    *
    * @param string $format_type
-   *   The format type
+   *   The format type.
    * @param string $context
    *   The context to prepare configuration for.
-   * @param array $properties
-   *   An array of formatter configuration.
-   *
+   * @param array $configuration
+   *   The configuration of the group.
    * @return array
    *   The display properties with defaults added.
    */
   public function prepareConfiguration($format_type, $context, array $configuration) {
     // Fill in defaults for missing properties.
-    $configuration += array(
+    $configuration += [
       'label' => '',
-      'settings' => array(),
-    );
+      'settings' => [],
+    ];
 
     // Fill in default settings values for the formatter.
     $configuration['settings'] += $this->getDefaultSettings($format_type, $context);
@@ -137,7 +134,7 @@ public function getDefaultSettings($type, $context) {
       $plugin_class = DefaultFactory::getPluginClass($type, $plugin_definition);
       return $plugin_class::defaultContextSettings($context);
     }
-    return array();
+    return [];
   }
 
 }
diff --git a/web/modules/field_group/src/FieldgroupUi.php b/web/modules/field_group/src/FieldgroupUi.php
index fa9514a6a355e922cb0910a8c7e5d2e2c2dfb205..1c0c98c54444c23e76cec8de89e91d95ae55dab9 100644
--- a/web/modules/field_group/src/FieldgroupUi.php
+++ b/web/modules/field_group/src/FieldgroupUi.php
@@ -1,6 +1,7 @@
 <?php
 
 namespace Drupal\field_group;
+
 use Drupal\Core\Url;
 use Drupal\field_ui\FieldUI;
 
@@ -11,7 +12,8 @@ class FieldgroupUi {
 
   /**
    * Get the field ui route that should be used for given arguments.
-   * @param stdClass $group
+   *
+   * @param object $group
    *   The group to get the field ui route for.
    *
    * @return \Drupal\Core\Url
@@ -52,12 +54,14 @@ public static function getFieldUiRoute($group) {
 
   /**
    * Get the field group delete route for a given group.
+   *
    * @param \stdClass $group
+   *   The group to delete.
    *
    * @return \Drupal\Core\Url
    *   A URL object.
    */
-  public static function getDeleteRoute($group) {
+  public static function getDeleteRoute(\stdClass $group) {
 
     $entity_type_id = $group->entity_type;
     $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
@@ -94,4 +98,4 @@ public static function getDeleteRoute($group) {
 
   }
 
-}
\ No newline at end of file
+}
diff --git a/web/modules/field_group/src/Form/FieldGroupAddForm.php b/web/modules/field_group/src/Form/FieldGroupAddForm.php
index de37914cda6395002310e1277a3ad446da3a4b4a..987a3757b2c33b715e9c545d88736b217e904efe 100644
--- a/web/modules/field_group/src/Form/FieldGroupAddForm.php
+++ b/web/modules/field_group/src/Form/FieldGroupAddForm.php
@@ -4,8 +4,12 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\field_group\FieldGroupFormatterPluginManager;
 use Drupal\field_group\FieldgroupUi;
+use Drupal\field_group\FormatterHelper;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a form for adding a fieldgroup to a bundle.
@@ -54,6 +58,43 @@ class FieldGroupAddForm extends FormBase {
    */
   protected $currentStep;
 
+  /**
+   * The field group formatter plugin manager.
+   *
+   * @var \Drupal\field_group\FieldGroupFormatterPluginManager
+   */
+  protected $fieldGroupFormatterPluginManager;
+
+  /**
+   * The messenger.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
+  /**
+   * FieldGroupAddForm constructor.
+   *
+   * @param \Drupal\field_group\FieldGroupFormatterPluginManager $fieldGroupFormatterPluginManager
+   *   The field group formatter plugin manager.
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger.
+   */
+  public function __construct(FieldGroupFormatterPluginManager $fieldGroupFormatterPluginManager, MessengerInterface $messenger) {
+    $this->fieldGroupFormatterPluginManager = $fieldGroupFormatterPluginManager;
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.field_group.formatters'),
+      $container->get('messenger')
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -66,6 +107,10 @@ public function getFormId() {
    */
   public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL, $context = NULL) {
 
+    $this->entityTypeId = $entity_type_id;
+    $this->bundle = $bundle;
+    $this->context = $context;
+
     if ($context == 'form') {
       $this->mode = \Drupal::request()->get('form_mode_name');
     }
@@ -77,22 +122,9 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t
       $this->mode = 'default';
     }
 
-    if (!$form_state->get('context')) {
-      $form_state->set('context', $context);
-    }
-    if (!$form_state->get('entity_type_id')) {
-      $form_state->set('entity_type_id', $entity_type_id);
-    }
-    if (!$form_state->get('bundle')) {
-      $form_state->set('bundle', $bundle);
-    }
     if (!$form_state->get('step')) {
       $form_state->set('step', 'formatter');
     }
-
-    $this->entityTypeId = $form_state->get('entity_type_id');
-    $this->bundle = $form_state->get('bundle');
-    $this->context = $form_state->get('context');
     $this->currentStep = $form_state->get('step');
 
     if ($this->currentStep == 'formatter') {
@@ -103,46 +135,45 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t
     }
 
     return $form;
-
   }
 
   /**
    * Build the formatter selection step.
    */
-  function buildFormatterSelectionForm(array &$form, FormStateInterface $form_state) {
+  public function buildFormatterSelectionForm(array &$form, FormStateInterface $form_state) {
 
     // Gather group formatters.
-    $formatter_options = \field_group_field_formatter_options($form_state->get('context'));
-    $form['add'] = array(
+    $formatter_options = FormatterHelper::formatterOptions($this->context);
+    $form['add'] = [
       '#type' => 'container',
-      '#attributes' => array('class' => array('form--inline', 'clearfix')),
-    );
+      '#attributes' => ['class' => ['form--inline', 'clearfix']],
+    ];
 
-    $form['add']['group_formatter'] = array(
+    $form['add']['group_formatter'] = [
       '#type' => 'select',
       '#title' => $this->t('Add a new group'),
       '#options' => $formatter_options,
       '#empty_option' => $this->t('- Select a group type -'),
       '#required' => TRUE,
-    );
+    ];
 
     // Field label and field_name.
-    $form['new_group_wrapper'] = array(
+    $form['new_group_wrapper'] = [
       '#type' => 'container',
-      '#states' => array(
-        '!visible' => array(
-          ':input[name="group_formatter"]' => array('value' => ''),
-        ),
-      ),
-    );
-    $form['new_group_wrapper']['label'] = array(
+      '#states' => [
+        '!visible' => [
+          ':input[name="group_formatter"]' => ['value' => ''],
+        ],
+      ],
+    ];
+    $form['new_group_wrapper']['label'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Label'),
       '#size' => 15,
       '#required' => TRUE,
-    );
+    ];
 
-    $form['new_group_wrapper']['group_name'] = array(
+    $form['new_group_wrapper']['group_name'] = [
       '#type' => 'machine_name',
       '#size' => 15,
       // This field should stay LTR even for RTL languages.
@@ -150,22 +181,22 @@ function buildFormatterSelectionForm(array &$form, FormStateInterface $form_stat
       '#field_suffix' => '</span>&lrm;',
       '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
       '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen(self::GROUP_PREFIX),
-      '#machine_name' => array(
-        'source' => array('new_group_wrapper', 'label'),
-        'exists' => array($this, 'groupNameExists'),
-      ),
+      '#machine_name' => [
+        'source' => ['new_group_wrapper', 'label'],
+        'exists' => [$this, 'groupNameExists'],
+      ],
       '#required' => TRUE,
-    );
+    ];
 
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
+    $form['actions'] = ['#type' => 'actions'];
+    $form['actions']['submit'] = [
       '#type' => 'submit',
       '#value' => $this->t('Save and continue'),
       '#button_type' => 'primary',
-      '#validate' => array(
-        array($this, 'validateFormatterSelection')
-      ),
-    );
+      '#validate' => [
+        [$this, 'validateFormatterSelection'],
+      ],
+    ];
 
     $form['#attached']['library'][] = 'field_ui/drupal.field_ui';
   }
@@ -173,7 +204,7 @@ function buildFormatterSelectionForm(array &$form, FormStateInterface $form_stat
   /**
    * Build the formatter configuration form.
    */
-  function buildConfigurationForm(array &$form, FormStateInterface $form_state) {
+  public function buildConfigurationForm(array &$form, FormStateInterface $form_state) {
 
     $group = new \stdClass();
     $group->context = $this->context;
@@ -182,27 +213,27 @@ function buildConfigurationForm(array &$form, FormStateInterface $form_state) {
     $group->mode = $this->mode;
 
     $manager = \Drupal::service('plugin.manager.field_group.formatters');
-    $plugin = $manager->getInstance(array(
+    $plugin = $manager->getInstance([
       'format_type' => $form_state->getValue('group_formatter'),
       'configuration' => [
         'label' => $form_state->getValue('label'),
       ],
       'group' => $group,
-    ));
+    ]);
 
-    $form['format_settings'] = array(
+    $form['format_settings'] = [
       '#type' => 'container',
       '#tree' => TRUE,
-    );
+    ];
 
     $form['format_settings'] += $plugin->settingsForm();
 
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
+    $form['actions'] = ['#type' => 'actions'];
+    $form['actions']['submit'] = [
       '#type' => 'submit',
       '#value' => $this->t('Create group'),
       '#button_type' => 'primary',
-    );
+    ];
 
   }
 
@@ -231,29 +262,29 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     }
     else {
 
-      $new_group = (object) array(
+      $new_group = (object) [
         'group_name' => $form_state->get('group_name'),
         'entity_type' => $this->entityTypeId,
         'bundle' => $this->bundle,
         'mode' => $this->mode,
         'context' => $this->context,
-        'children' =>[],
+        'children' => [],
         'parent_name' => '',
         'weight' => 20,
         'format_type' => $form_state->get('group_formatter'),
-      );
+      ];
 
       $new_group->format_settings = $form_state->getValue('format_settings');
       $new_group->label = $new_group->format_settings['label'];
       unset($new_group->format_settings['label']);
-      $new_group->format_settings += _field_group_get_default_formatter_settings($form_state->get('group_formatter'), $this->context);
+      $new_group->format_settings += $this->fieldGroupFormatterPluginManager->getDefaultSettings($form_state->get('group_formatter'), $this->context);
 
       field_group_group_save($new_group);
 
       // Store new group information for any additional submit handlers.
       $groups_added = $form_state->get('groups_added');
       $groups_added['_add_new_group'] = $new_group->group_name;
-      drupal_set_message(t('New group %label successfully created.', array('%label' => $new_group->label)));
+      $this->messenger->addMessage(t('New group %label successfully created.', ['%label' => $new_group->label]));
 
       $form_state->setRedirectUrl(FieldgroupUi::getFieldUiRoute($new_group));
       \Drupal::cache()->invalidate('field_groups');
@@ -269,22 +300,18 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    *   The machine name, not prefixed.
    * @param array $element
    *   An array containing the structure of the 'group_name' element.
-   * @param FormStateInterface $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
    *
    * @return bool
    *   Whether or not the group machine name is taken.
    */
-  public function groupNameExists($value, $element, FormStateInterface $form_state) {
+  public function groupNameExists($value, array $element, FormStateInterface $form_state) {
 
     // Add the prefix.
     $group_name = self::GROUP_PREFIX . $value;
-    $entity_type = $form_state->get('entity_type_id');
-    $bundle = $form_state->get('bundle');
-    $context = $form_state->get('context');
-    $mode = $form_state->get('mode');
 
-    return field_group_exists($group_name, $entity_type, $bundle, $context, $mode);
+    return field_group_exists($group_name, $this->entityTypeId, $this->bundle, $this->context, $this->mode);
   }
 
 }
diff --git a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
index 1b827292343aac1d99ebfbf63483405a138aa021..3cf86b88f90b9aff18a184fe0e4e2f54f838a058 100644
--- a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
+++ b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
@@ -4,7 +4,9 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\field_group\FieldgroupUi;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a form for removing a fieldgroup from a bundle.
@@ -14,10 +16,36 @@ class FieldGroupDeleteForm extends ConfirmFormBase {
   /**
    * The fieldgroup to delete.
    *
-   * @var stdClass
+   * @var object
    */
   protected $fieldGroup;
 
+  /**
+   * The messenger.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
+  /**
+   * FieldGroupDeleteForm constructor.
+   *
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger.
+   */
+  public function __construct(MessengerInterface $messenger) {
+    $this->messenger = $messenger;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('messenger')
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -25,6 +53,9 @@ public function getFormId() {
     return 'field_group_delete_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state, $field_group_name = NULL, $entity_type_id = NULL, $bundle = NULL, $context = NULL) {
 
     if ($context == 'form') {
@@ -46,12 +77,12 @@ public function buildForm(array $form, FormStateInterface $form_state, $field_gr
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $bundles = entity_get_bundles();
+    $bundles = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo();
     $bundle_label = $bundles[$this->fieldGroup->entity_type][$this->fieldGroup->bundle]['label'];
 
     field_group_group_delete($this->fieldGroup);
 
-    drupal_set_message(t('The group %group has been deleted from the %type content type.', array('%group' => t($this->fieldGroup->label), '%type' => $bundle_label)));
+    $this->messenger->addMessage(t('The group %group has been deleted from the %type content type.', ['%group' => t($this->fieldGroup->label), '%type' => $bundle_label]));
 
     // Redirect.
     $form_state->setRedirectUrl($this->getCancelUrl());
@@ -62,7 +93,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return $this->t('Are you sure you want to delete the group %group?', array('%group' => t($this->fieldGroup->label)));
+    return $this->t('Are you sure you want to delete the group %group?', ['%group' => t($this->fieldGroup->label)]);
   }
 
   /**
diff --git a/web/modules/field_group/src/FormatterHelper.php b/web/modules/field_group/src/FormatterHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..436d7d71cac25597bb4919dc69395f7aaf52a28a
--- /dev/null
+++ b/web/modules/field_group/src/FormatterHelper.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\field_group;
+
+use Drupal;
+
+/**
+ * Static methods for fieldgroup formatters.
+ */
+class FormatterHelper {
+
+  /**
+   * Return an array of field_group_formatter options.
+   */
+  public static function formatterOptions($type) {
+    $options = &drupal_static(__FUNCTION__);
+
+    if (!isset($options)) {
+      $options = [];
+
+      $manager = Drupal::service('plugin.manager.field_group.formatters');
+      $formatters = $manager->getDefinitions();
+
+      foreach ($formatters as $formatter) {
+        if (in_array($type, $formatter['supported_contexts'])) {
+          $options[$formatter['id']] = $formatter['label'];
+        }
+      }
+    }
+
+    return $options;
+  }
+
+}
diff --git a/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php b/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php
index 96bd638bb75d59cc201e61d9c8b3135df9dfc3c4..64972b603c04eb0c0beb0ff72354a7cc26f95de0 100644
--- a/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php
+++ b/web/modules/field_group/src/Plugin/Derivative/FieldGroupLocalAction.php
@@ -57,7 +57,7 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $this->derivatives = array();
+    $this->derivatives = [];
 
     foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
       if ($entity_type->get('field_ui_base_route')) {
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php
index 378f5897f5b0ba0e4b46f912d12b869a9510c30d..75444dfd71799fc73f5c40416c94520679fc27c3 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Accordion.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter;
 
+use Drupal\field_group\Element\Accordion as AccordionElement;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Form\FormState;
 use Drupal\field_group\FieldGroupFormatterBase;
@@ -24,26 +25,35 @@ class Accordion extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
 
-    $form_state = new FormState();
+    // Keep using preRender parent for BC.
+    parent::preRender($element, $processed_object);
 
-    $element += array(
+    $element += [
       '#type' => 'field_group_accordion',
       '#effect' => $this->getSetting('effect'),
-    );
+    ];
 
     if ($this->getSetting('id')) {
-      $element['#id'] = Html::getId($this->getSetting('id'));
+      $element['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     $classes = $this->getClasses();
     if (!empty($classes)) {
-      $element += array('#attributes' => array('class' => $classes));
+      $element += ['#attributes' => ['class' => $classes]];
     }
 
-    \Drupal\field_group\Element\Accordion::processAccordion($element, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    $this->process($element, $rendering_object);
+
+    $form_state = new FormState();
+    AccordionElement::processAccordion($element, $form_state);
   }
 
   /**
@@ -53,13 +63,13 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['effect'] = array(
+    $form['effect'] = [
       '#title' => $this->t('Effect'),
       '#type' => 'select',
-      '#options' => array('none' => $this->t('None'), 'bounceslide' => $this->t('Bounce slide')),
+      '#options' => ['none' => $this->t('None'), 'bounceslide' => $this->t('Bounce slide')],
       '#default_value' => $this->getSetting('effect'),
       '#weight' => 2,
-    );
+    ];
 
     return $form;
   }
@@ -69,9 +79,9 @@ public function settingsForm() {
    */
   public function settingsSummary() {
 
-    $summary = array();
+    $summary = [];
     $summary[] = $this->t('Effect : @effect',
-      array('@effect' => $this->getSetting('effect'))
+      ['@effect' => $this->getSetting('effect')]
     );
 
     return $summary;
@@ -81,9 +91,9 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    return array(
+    return [
       'effect' => 'none',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
   }
 
 }
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
index a92ee3c09f2425fe15505221e72915222ae0554d..afab3bc4a119c698a8c55acfc802d24e2e79b5ae 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter;
 
-use Drupal;
 use Drupal\Component\Utility\Html;
 use Drupal\field_group\FieldGroupFormatterBase;
 
@@ -28,29 +27,48 @@ class AccordionItem extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
 
-    $element += array(
+    // Keep using preRender parent for BC.
+    parent::preRender($element, $processed_object);
+
+    $element += [
       '#type' => 'field_group_accordion_item',
-      '#open' => $this->getSetting('formatter') == 'open' ? TRUE : FALSE,
-      '#description' => $this->getSetting('description'),
-      '#title' => Drupal::translation()->translate($this->getLabel()),
-    );
+      '#effect' => $this->getSetting('effect'),
+      '#title' => Html::escape($this->t($this->getLabel())),
+    ];
 
     if ($this->getSetting('id')) {
-      $element['#id'] = Html::getId($this->getSetting('id'));
+      $element['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     $classes = $this->getClasses();
     if (!empty($classes)) {
-      $element += array('#attributes' => array('class' => $classes));
+      $element += ['#attributes' => ['class' => $classes]];
     }
 
     if ($this->getSetting('required_fields')) {
       $element['#attached']['library'][] = 'field_group/formatter.details';
     }
 
+    if ($this->getSetting('formatter') == 'open') {
+        $element['#open'] = TRUE;
+    }
+
+    foreach ($element as $key => $value) {
+      if (is_array($value) && !empty($value['#children_errors'])) {
+        $element['#open'] = TRUE;
+      }
+    }
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    parent::preRender($element, $rendering_object);
+    $this->process($element, $rendering_object);
   }
 
   /**
@@ -60,21 +78,21 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['formatter'] = array(
+    $form['formatter'] = [
       '#title' => $this->t('Default state'),
       '#type' => 'select',
       '#options' => array_combine($this->pluginDefinition['format_types'], $this->pluginDefinition['format_types']),
       '#default_value' => $this->getSetting('formatter'),
       '#weight' => -4,
-    );
+    ];
 
     if ($this->context == 'form') {
-      $form['required_fields'] = array(
+      $form['required_fields'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Mark group as required if it contains required fields.'),
         '#default_value' => $this->getSetting('required_fields'),
         '#weight' => 2,
-      );
+      ];
     }
 
     return $form;
@@ -85,7 +103,7 @@ public function settingsForm() {
    */
   public function settingsSummary() {
 
-    $summary = array();
+    $summary = [];
 
     if ($this->getSetting('required_fields')) {
       $summary[] = $this->t('Mark as required');
@@ -93,7 +111,7 @@ public function settingsSummary() {
 
     if ($this->getSetting('description')) {
       $summary[] = $this->t('Description : @description',
-        array('@description' => $this->getSetting('description'))
+        ['@description' => $this->getSetting('description')]
       );
     }
 
@@ -104,10 +122,10 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    $defaults = array(
+    $defaults = [
       'formatter' => 'closed',
       'description' => '',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
 
     if ($context == 'form') {
       $defaults['required_fields'] = 1;
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
index 8a78c6e820cc1a7d119ac9a696cff68928ed22cb..d1384cc1c65832a842fac5f52868117afe5ee053 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
@@ -23,36 +23,39 @@ class Details extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
 
-    $element += array(
+    $element += [
       '#type' => 'details',
       '#title' => Html::escape($this->t($this->getLabel())),
-      '#open' => $this->getSetting('open')
-    );
+      '#open' => $this->getSetting('open'),
+      '#description' => $this->getSetting('description'),
+    ];
 
     if ($this->getSetting('id')) {
-      $element['#id'] = Html::getId($this->getSetting('id'));
+      $element['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     $classes = $this->getClasses();
     if (!empty($classes)) {
-      $element += array(
-        '#attributes' => array('class' => $classes),
-      );
-    }
-
-    if ($this->getSetting('description')) {
-      $element += array(
-        '#description' => $this->getSetting('description'),
-      );
+      $element += [
+        '#attributes' => ['class' => $classes],
+      ];
     }
 
     if ($this->getSetting('required_fields')) {
       $element['#attached']['library'][] = 'field_group/formatter.details';
       $element['#attached']['library'][] = 'field_group/core';
     }
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    parent::preRender($element, $rendering_object);
+    $this->process($element, $rendering_object);
   }
 
   /**
@@ -61,19 +64,26 @@ public function preRender(&$element, $rendering_object) {
   public function settingsForm() {
     $form = parent::settingsForm();
 
-    $form['open'] = array(
+    $form['description'] = [
+      '#title' => $this->t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $this->getSetting('description'),
+      '#weight' => -4,
+    ];
+
+    $form['open'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Display element open by default.'),
       '#default_value' => $this->getSetting('open'),
-    );
+    ];
 
     if ($this->context == 'form') {
-      $form['required_fields'] = array(
+      $form['required_fields'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Mark group as required if it contains required fields.'),
         '#default_value' => $this->getSetting('required_fields'),
         '#weight' => 2,
-      );
+      ];
     }
 
     return $form;
@@ -84,7 +94,7 @@ public function settingsForm() {
    */
   public function settingsSummary() {
 
-    $summary = array();
+    $summary = [];
     if ($this->getSetting('open')) {
       $summary[] = $this->t('Default state open');
     }
@@ -103,10 +113,10 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    $defaults = array(
+    $defaults = [
       'open' => FALSE,
       'required_fields' => $context == 'form',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
 
     if ($context == 'form') {
       $defaults['required_fields'] = 1;
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
index ecbf217dacc81815d00933fac0a7a6a8c7479c64..4245b7ee35a19fb0a1a8e448b596ee2a76004b63 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
@@ -23,40 +23,42 @@ class Fieldset extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
+  public function process(&$element, $processed_object) {
 
-    $element += array(
+    $element += [
       '#type' => 'fieldset',
       '#title' => Html::escape($this->t($this->getLabel())),
-      '#pre_render' => array(),
-      '#attributes' => array(),
-    );
-
-    if ($this->getSetting('description')) {
-      $element += array(
-        '#description' => $this->getSetting('description'),
-      );
-
-      // When a fieldset has a description, an id is required.
-      if (!$this->getSetting('id')) {
-        $element['#id'] = Html::getId($this->group->group_name);
-      }
+      '#attributes' => [],
+      '#description' => $this->getSetting('description'),
+    ];
 
+    // When a fieldset has a description, an id is required.
+    if ($this->getSetting('description') && !$this->getSetting('id')) {
+      $element['#id'] = Html::getUniqueId($this->group->group_name);
     }
 
     if ($this->getSetting('id')) {
-      $element['#id'] = Html::getId($this->getSetting('id'));
+      $element['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     $classes = $this->getClasses();
     if (!empty($classes)) {
-      $element['#attributes'] += array('class' => $classes);
+      $element['#attributes'] += ['class' => $classes];
     }
 
     if ($this->getSetting('required_fields')) {
       $element['#attached']['library'][] = 'field_group/formatter.fieldset';
       $element['#attached']['library'][] = 'field_group/core';
     }
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    parent::preRender($element, $rendering_object);
+    $this->process($element, $rendering_object);
   }
 
   /**
@@ -66,20 +68,20 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['description'] = array(
+    $form['description'] = [
       '#title' => $this->t('Description'),
       '#type' => 'textarea',
       '#default_value' => $this->getSetting('description'),
       '#weight' => -4,
-    );
+    ];
 
     if ($this->context == 'form') {
-      $form['required_fields'] = array(
+      $form['required_fields'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Mark group as required if it contains required fields.'),
         '#default_value' => $this->getSetting('required_fields'),
         '#weight' => 2,
-      );
+      ];
     }
 
     return $form;
@@ -96,12 +98,6 @@ public function settingsSummary() {
       $summary[] = $this->t('Mark as required');
     }
 
-    if ($this->getSetting('description')) {
-      $summary[] = $this->t('Description : @description',
-        array('@description' => $this->getSetting('description'))
-      );
-    }
-
     return $summary;
   }
 
@@ -109,9 +105,9 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    $defaults = array(
+    $defaults = [
       'description' => '',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
 
     if ($context == 'form') {
       $defaults['required_fields'] = 1;
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
index 41f2d7e4e37f1aae5bc659c6051b4584ed8ae457..60e4d539c1655bb6e2296cf4fd8da70eda0429fb 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field_group\Plugin\field_group\FieldGroupFormatter;
 
+use Drupal\field_group\Element\HtmlElement as HtmlElementRenderElement;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Template\Attribute;
@@ -25,8 +26,10 @@ class HtmlElement extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
+
+    // Keep using preRender parent for BC.
+    parent::preRender($element, $processed_object);
 
     $element_attributes = new Attribute();
 
@@ -45,18 +48,18 @@ public function preRender(&$element, $rendering_object) {
 
     // Add the id to the attributes array.
     if ($this->getSetting('id')) {
-      $element_attributes['id'] = Html::getId($this->getSetting('id'));
+      $element_attributes['id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     // Add the classes to the attributes array.
     $classes = $this->getClasses();
     if (!empty($classes)) {
       if (!isset($element_attributes['class'])) {
-        $element_attributes['class'] = array();
+        $element_attributes['class'] = [];
       }
       // If user also entered class in the attributes textfield, force it to an array.
       else {
-        $element_attributes['class'] = array($element_attributes['class']);
+        $element_attributes['class'] = [$element_attributes['class']];
       }
       $element_attributes['class'] = array_merge($classes, $element_attributes['class']->value());
     }
@@ -69,10 +72,16 @@ public function preRender(&$element, $rendering_object) {
     if ($this->getSetting('show_label')) {
       $element['#title_element'] = $this->getSetting('label_element');
       $element['#title'] = Html::escape($this->t($this->getLabel()));
-    }
+      $element['#title_attributes'] = new Attribute();
 
-    $form_state = new FormState();
-    \Drupal\field_group\Element\HtmlElement::processHtmlElement($element, $form_state);
+      if (!empty($this->getSetting('label_element_classes'))) {
+        $element['#title_attributes']->addClass(explode(' ', $this->getSetting('label_element_classes')));
+      }
+
+      if (!empty($this->getSetting('effect')) && $this->getSetting('effect') !== 'none') {
+        $element['#title_attributes']->addClass('field-group-toggler');
+      }
+    }
 
     if ($this->getSetting('required_fields')) {
       $element['#attributes']['class'][] = 'field-group-html-element';
@@ -81,6 +90,16 @@ public function preRender(&$element, $rendering_object) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    $this->process($element, $rendering_object);
+
+    $form_state = new FormState();
+    HtmlElementRenderElement::processHtmlElement($element, $form_state);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -88,81 +107,93 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['element'] = array(
+    $form['element'] = [
       '#title' => $this->t('Element'),
       '#type' => 'textfield',
       '#default_value' => $this->getSetting('element'),
       '#description' => $this->t('E.g. div, section, aside etc.'),
       '#weight' => 1,
-    );
+    ];
 
-    $form['show_label'] = array(
+    $form['show_label'] = [
       '#title' => $this->t('Show label'),
       '#type' => 'select',
-      '#options' => array(0 => $this->t('No'), 1 => $this->t('Yes')),
+      '#options' => [0 => $this->t('No'), 1 => $this->t('Yes')],
       '#default_value' => $this->getSetting('show_label'),
       '#weight' => 2,
-      '#attributes' => array(
-        'data-fieldgroup-selector' => 'show_label'
-      ),
-    );
+      '#attributes' => [
+        'data-fieldgroup-selector' => 'show_label',
+      ],
+    ];
 
-    $form['label_element'] = array(
+    $form['label_element'] = [
       '#title' => $this->t('Label element'),
       '#type' => 'textfield',
       '#default_value' => $this->getSetting('label_element'),
       '#weight' => 3,
-      '#states' => array(
-        'visible' => array(
-          ':input[data-fieldgroup-selector="show_label"]' => array('value' => 1),
-        ),
-      ),
-    );
+      '#states' => [
+        'visible' => [
+          ':input[data-fieldgroup-selector="show_label"]' => ['value' => 1],
+        ],
+      ],
+    ];
+
+    $form['label_element_classes'] = [
+      '#title' => $this->t('Label element HTML classes'),
+      '#type' => 'textfield',
+      '#default_value' => $this->getSetting('label_element_classes'),
+      '#weight' => 3,
+      '#states' => [
+        'visible' => [
+          ':input[data-fieldgroup-selector="show_label"]' => ['value' => 1],
+        ],
+      ],
+    ];
 
     if ($this->context == 'form') {
-      $form['required_fields'] = array(
+      $form['required_fields'] = [
         '#title' => $this->t('Mark group as required if it contains required fields.'),
         '#type' => 'checkbox',
         '#default_value' => $this->getSetting('required_fields'),
         '#weight' => 4,
-      );
+      ];
     }
 
-    $form['attributes'] = array(
+    $form['attributes'] = [
       '#title' => $this->t('Attributes'),
       '#type' => 'textfield',
       '#default_value' => $this->getSetting('attributes'),
       '#description' => $this->t('E.g. name="anchor"'),
       '#weight' => 5,
-    );
+    ];
 
-    $form['effect'] = array(
+    $form['effect'] = [
       '#title' => $this->t('Effect'),
       '#type' => 'select',
-      '#options' => array(
+      '#options' => [
         'none' => $this->t('None'),
         'collapsible' => $this->t('Collapsible'),
-        'blind' => $this->t('Blind')
-      ),
+        'blind' => $this->t('Blind'),
+      ],
       '#default_value' => $this->getSetting('effect'),
       '#weight' => 6,
-      '#attributes' => array(
-        'data-fieldgroup-selector' => 'effect'
-      ),
-    );
+      '#attributes' => [
+        'data-fieldgroup-selector' => 'effect',
+      ],
+    ];
 
-    $form['speed'] = array(
+    $form['speed'] = [
       '#title' => $this->t('Speed'),
       '#type' => 'select',
-      '#options' => array('slow' => $this->t('Slow'), 'fast' => $this->t('Fast')),
+      '#options' => ['slow' => $this->t('Slow'), 'fast' => $this->t('Fast')],
       '#default_value' => $this->getSetting('speed'),
       '#weight' => 7,
-      '#states' => array(
-        '!visible' => array(
-          ':input[data-fieldgroup-selector="effect"]' => array('value' => 'none'),
-        ),
-      ),
-    );
+      '#states' => [
+        '!visible' => [
+          ':input[data-fieldgroup-selector="effect"]' => ['value' => 'none'],
+        ],
+      ],
+    ];
 
     return $form;
   }
@@ -174,18 +205,23 @@ public function settingsSummary() {
 
     $summary = parent::settingsSummary();
     $summary[] = $this->t('Element: @element',
-      array('@element' => $this->getSetting('element'))
+      ['@element' => $this->getSetting('element')]
     );
 
     if ($this->getSetting('show_label')) {
       $summary[] = $this->t('Label element: @element',
-        array('@element' => $this->getSetting('label_element'))
+        ['@element' => $this->getSetting('label_element')]
       );
+      if (!empty($this->getSetting('label_element_classes'))) {
+        $summary[] = $this->t('Label element HTML classes: @label_classes', [
+          '@label_classes' => $this->getSetting('label_element_classes'),
+        ]);
+      }
     }
 
     if ($this->getSetting('attributes')) {
       $summary[] = $this->t('Attributes: @attributes',
-        array('@attributes' => $this->getSetting('attributes'))
+        ['@attributes' => $this->getSetting('attributes')]
       );
     }
 
@@ -200,14 +236,15 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    $defaults = array(
+    $defaults = [
       'element' => 'div',
       'show_label' => 0,
       'label_element' => 'h3',
+      'label_element_classes' => '',
       'effect' => 'none',
       'speed' => 'fast',
       'attributes' => '',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
 
     if ($context == 'form') {
       $defaults['required_fields'] = 1;
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php
index 7cc8a64456d1c7b874240787531b77d64be5cde7..fe58da6dfb16c6f1732d0d1e324b4d4187a5b7e4 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tab.php
@@ -19,7 +19,7 @@
  *   supported_contexts = {
  *     "form",
  *     "view",
- *   },
+ *   }
  * )
  */
 class Tab extends FieldGroupFormatterBase {
@@ -27,40 +27,36 @@ class Tab extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
 
-    $add = array(
+    // Keep using preRender parent for BC.
+    parent::preRender($element, $processed_object);
+
+    $add = [
       '#type' => 'details',
       '#title' => Html::escape($this->t($this->getLabel())),
       '#description' => $this->getSetting('description'),
-    );
+      '#group' => $this->group->parent_name,
+    ];
 
     if ($this->getSetting('id')) {
-      $add['#id'] = Html::getId($this->getSetting('id'));
+      $add['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
     else {
-      $add['#id'] = Html::getId('edit-' . $this->group->group_name);
+      $add['#id'] = Html::getUniqueId('edit-' . $this->group->group_name);
     }
 
     $classes = $this->getClasses();
     if (!empty($classes)) {
-      $element += array(
-        '#attributes' => array('class' => $classes),
-      );
+      $element += [
+        '#attributes' => ['class' => $classes],
+      ];
     }
 
     if ($this->getSetting('formatter') == 'open') {
       $element['#open'] = TRUE;
     }
 
-    // Front-end and back-end on configuration will lead
-    // to vertical tabs nested in a separate vertical group.
-    if (!empty($this->group->parent_name)) {
-      $add['#group'] = $this->group->parent_name;
-      $add['#parents'] = array($add['#group']);
-    }
-
     if ($this->getSetting('required_fields')) {
       $element['#attached']['library'][] = 'field_group/formatter.tabs';
       $element['#attached']['library'][] = 'field_group/core';
@@ -70,6 +66,14 @@ public function preRender(&$element, $rendering_object) {
 
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+    parent::preRender($element, $rendering_object);
+    $this->process($element, $rendering_object);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -77,28 +81,28 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['formatter'] = array(
+    $form['description'] = [
+      '#title' => $this->t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => $this->getSetting('description'),
+      '#weight' => -4,
+    ];
+
+    $form['formatter'] = [
       '#title' => $this->t('Default state'),
       '#type' => 'select',
       '#options' => array_combine($this->pluginDefinition['format_types'], $this->pluginDefinition['format_types']),
       '#default_value' => $this->getSetting('formatter'),
       '#weight' => -4,
-    );
-
-    $form['description'] = array(
-      '#title' => $this->t('Description'),
-      '#type' => 'textarea',
-      '#default_value' => $this->getSetting('description'),
-      '#weight' => -4,
-    );
+    ];
 
     if ($this->context == 'form') {
-      $form['required_fields'] = array(
+      $form['required_fields'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Mark group as required if it contains required fields.'),
         '#default_value' => $this->getSetting('required_fields'),
         '#weight' => 2,
-      );
+      ];
     }
 
     return $form;
@@ -108,10 +112,10 @@ public function settingsForm() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    $defaults = array(
+    $defaults = [
       'formatter' => 'closed',
       'description' => '',
-    ) + parent::defaultSettings($context);
+    ] + parent::defaultSettings($context);
 
     if ($context == 'form') {
       $defaults['required_fields'] = 1;
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
index 4f49ec33438fe36674f05ecb327bd654478c3db4..56d58d45dbe2c49c1a5a73a835f5697055c8fdbc 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
@@ -27,19 +27,21 @@ class Tabs extends FieldGroupFormatterBase {
   /**
    * {@inheritdoc}
    */
-  public function preRender(&$element, $rendering_object) {
-    parent::preRender($element, $rendering_object);
+  public function process(&$element, $processed_object) {
+
+    // Keep using preRender parent for BC.
+    parent::preRender($element, $processed_object);
 
-    $element += array(
-      '#prefix' => '<div class=" ' . implode(' ' , $this->getClasses()) . '">',
+    $element += [
+      '#prefix' => '<div class=" ' . implode(' ', $this->getClasses()) . '">',
       '#suffix' => '</div>',
       '#tree' => TRUE,
-      '#parents' => array($this->group->group_name),
+      '#parents' => [$this->group->group_name],
       '#default_tab' => '',
-    );
+    ];
 
     if ($this->getSetting('id')) {
-      $element['#id'] = Html::getId($this->getSetting('id'));
+      $element['#id'] = Html::getUniqueId($this->getSetting('id'));
     }
 
     // By default tabs don't have titles but you can override it in the theme.
@@ -47,39 +49,44 @@ public function preRender(&$element, $rendering_object) {
       $element['#title'] = Html::escape($this->getLabel());
     }
 
-    $form_state = new FormState();
+    $element += [
+      '#type' => $this->getSetting('direction') . '_tabs',
+      '#theme_wrappers' => [$this->getSetting('direction') . '_tabs'],
+    ];
 
-    if ($this->getSetting('direction') == 'vertical') {
+    // Search for a tab that was marked as open. First one wins.
+    foreach (Element::children($element) as $tab_name) {
+      if (!empty($element[$tab_name]['#open'])) {
+        $element[$this->group->group_name . '__active_tab']['#default_value'] = $tab_name;
+        break;
+      }
+    }
 
-      $element += array(
-        '#type' => 'vertical_tabs',
-        '#theme_wrappers' => array('vertical_tabs'),
-      );
-      $complete_form = array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preRender(&$element, $rendering_object) {
+
+    $this->process($element, $rendering_object);
+
+    if ($this->getSetting('direction') == 'vertical') {
+      $form_state = new FormState();
+      $complete_form = [];
       $element = VerticalTabs::processVerticalTabs($element, $form_state, $complete_form);
     }
     else {
-      $element += array(
-        '#type' => 'horizontal_tabs',
-        '#theme_wrappers' => array('horizontal_tabs'),
-      );
-      $on_form = $this->context == 'form';
-      $element = HorizontalTabs::processHorizontalTabs($element, $form_state, $on_form);
+      $form_state = new FormState();
+      $complete_form = [];
+      $element = HorizontalTabs::processHorizontalTabs($element, $form_state, $complete_form);
     }
 
     // Make sure the group has 1 child. This is needed to succeed at form_pre_render_vertical_tabs().
     // Skipping this would force us to move all child groups to this array, making it an un-nestable.
-    $element['group']['#groups'][$this->group->group_name] = array(0 => array());
+    $element['group']['#groups'][$this->group->group_name] = [0 => []];
     $element['group']['#groups'][$this->group->group_name]['#group_exists'] = TRUE;
 
-    // Search for a tab that was marked as open. First one wins.
-    foreach (Element::children($element) as $tab_name) {
-      if (!empty($element[$tab_name]['#open'])) {
-        $element[$this->group->group_name . '__active_tab']['#default_value'] = $tab_name;
-        break;
-      }
-    }
-
   }
 
   /**
@@ -89,16 +96,16 @@ public function settingsForm() {
 
     $form = parent::settingsForm();
 
-    $form['direction'] = array(
+    $form['direction'] = [
       '#title' => $this->t('Direction'),
       '#type' => 'select',
-      '#options' => array(
+      '#options' => [
         'vertical' => $this->t('Vertical'),
         'horizontal' => $this->t('Horizontal'),
-      ),
+      ],
       '#default_value' => $this->getSetting('direction'),
       '#weight' => 1,
-    );
+    ];
 
     return $form;
   }
@@ -110,7 +117,7 @@ public function settingsSummary() {
 
     $summary = parent::settingsSummary();
     $summary[] = $this->t('Direction: @direction',
-      array('@direction' => $this->getSetting('direction'))
+      ['@direction' => $this->getSetting('direction')]
     );
 
     return $summary;
@@ -120,9 +127,9 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   public static function defaultContextSettings($context) {
-    return array(
+    return [
       'direction' => 'vertical',
-    ) + parent::defaultContextSettings($context);
+    ] + parent::defaultContextSettings($context);
   }
 
   /**
diff --git a/web/modules/field_group/src/Routing/FieldGroupConverter.php b/web/modules/field_group/src/Routing/FieldGroupConverter.php
index 3eb620e65b1d6510fcde0f3dacbfa9a1e30082a9..9dd44473896f2e07442e02a357364d516d7009da 100644
--- a/web/modules/field_group/src/Routing/FieldGroupConverter.php
+++ b/web/modules/field_group/src/Routing/FieldGroupConverter.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field_group\Routing;
 
+use Symfony\Component\Routing\Route;
 use Drupal\Core\ParamConverter\ParamConverterInterface;
 
 /**
@@ -12,7 +13,7 @@ class FieldGroupConverter implements ParamConverterInterface {
   /**
    * {@inheritdoc}
    */
-  public function applies($definition, $name, \Symfony\Component\Routing\Route $route) {
+  public function applies($definition, $name, Route $route) {
     return isset($definition['type']) && $definition['type'] == 'field_group';
   }
 
@@ -28,5 +29,4 @@ public function convert($value, $definition, $name, array $defaults) {
     return field_group_load_field_group($identifiers[4], $identifiers[0], $identifiers[1], $identifiers[2], $identifiers[3]);
   }
 
-
 }
diff --git a/web/modules/field_group/src/Routing/RouteSubscriber.php b/web/modules/field_group/src/Routing/RouteSubscriber.php
index 9a7f5397cb06e1fd07de5e8418049ee3d03f091d..2ca276b2d24683a34a630f92137b858f881ac040 100644
--- a/web/modules/field_group/src/Routing/RouteSubscriber.php
+++ b/web/modules/field_group/src/Routing/RouteSubscriber.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\field_group\Routing;
 
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Routing\RouteSubscriberBase;
 use Drupal\Core\Routing\RoutingEvents;
 use Symfony\Component\Routing\Route;
@@ -14,20 +14,20 @@
 class RouteSubscriber extends RouteSubscriberBase {
 
   /**
-   * The entity type manager
+   * The entity type manager.
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
-  protected $manager;
+  protected $entityTypeManager;
 
   /**
    * Constructs a RouteSubscriber object.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $manager
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
    */
-  public function __construct(EntityManagerInterface $manager) {
-    $this->manager = $manager;
+  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
@@ -36,8 +36,8 @@ public function __construct(EntityManagerInterface $manager) {
   protected function alterRoutes(RouteCollection $collection) {
 
     // Create fieldgroup routes for every entity.
-    foreach ($this->manager->getDefinitions() as $entity_type_id => $entity_type) {
-      $defaults = array();
+    foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
+      $defaults = [];
       if ($route_name = $entity_type->get('field_ui_base_route')) {
         // Try to get the route from the current collection.
         if (!$entity_route = $collection->get($route_name)) {
@@ -51,15 +51,15 @@ protected function alterRoutes(RouteCollection $collection) {
         $options['_field_ui'] = TRUE;
 
         if (($bundle_entity_type = $entity_type->getBundleEntityType()) && $bundle_entity_type !== 'bundle') {
-          $options['parameters'][$entity_type->getBundleEntityType()] = array(
+          $options['parameters'][$entity_type->getBundleEntityType()] = [
             'type' => 'entity:' . $entity_type->getBundleEntityType(),
-          );
+          ];
         }
 
-        $options['parameters']['field_group'] = array(
+        $options['parameters']['field_group'] = [
           'type' => 'field_group',
           'entity_type' => $entity_type->getBundleEntityType(),
-        );
+        ];
 
         $defaults_delete = [
           'entity_type_id' => $entity_type_id,
@@ -82,7 +82,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/form-display/{field_group_name}/delete",
           ['context' => 'form'] + $defaults_delete,
-          array('_permission' => 'administer ' . $entity_type_id . ' form display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' form display'],
           $options
         );
         $collection->add("field_ui.field_group_delete_$entity_type_id.form_display", $route);
@@ -90,7 +90,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/form-display/{form_mode_name}/{field_group_name}/delete",
           ['context' => 'form'] + $defaults_delete,
-          array('_permission' => 'administer ' . $entity_type_id . ' form display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' form display'],
           $options
         );
         $collection->add("field_ui.field_group_delete_$entity_type_id.form_display.form_mode", $route);
@@ -98,7 +98,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/display/{field_group_name}/delete",
           ['context' => 'view'] + $defaults_delete,
-          array('_permission' => 'administer ' . $entity_type_id . ' display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' display'],
           $options
         );
         $collection->add("field_ui.field_group_delete_$entity_type_id.display", $route);
@@ -106,7 +106,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/display/{view_mode_name}/{field_group_name}/delete",
           ['context' => 'view'] + $defaults_delete,
-          array('_permission' => 'administer ' . $entity_type_id . ' display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' display'],
           $options
         );
         $collection->add("field_ui.field_group_delete_$entity_type_id.display.view_mode", $route);
@@ -115,7 +115,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/form-display/add-group",
           ['context' => 'form'] + $defaults_add,
-          array('_permission' => 'administer ' . $entity_type_id . ' form display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' form display'],
           $options
         );
         $collection->add("field_ui.field_group_add_$entity_type_id.form_display", $route);
@@ -123,7 +123,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/form-display/{form_mode_name}/add-group",
           ['context' => 'form'] + $defaults_add,
-          array('_permission' => 'administer ' . $entity_type_id . ' form display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' form display'],
           $options
         );
         $collection->add("field_ui.field_group_add_$entity_type_id.form_display.form_mode", $route);
@@ -131,7 +131,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/display/add-group",
           ['context' => 'view'] + $defaults_add,
-          array('_permission' => 'administer ' . $entity_type_id . ' display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' display'],
           $options
         );
         $collection->add("field_ui.field_group_add_$entity_type_id.display", $route);
@@ -139,7 +139,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/display/{view_mode_name}/add-group",
           ['context' => 'view'] + $defaults_add,
-          array('_permission' => 'administer ' . $entity_type_id . ' display'),
+          ['_permission' => 'administer ' . $entity_type_id . ' display'],
           $options
         );
         $collection->add("field_ui.field_group_add_$entity_type_id.display.view_mode", $route);
@@ -152,9 +152,9 @@ protected function alterRoutes(RouteCollection $collection) {
    * {@inheritdoc}
    */
   public static function getSubscribedEvents() {
-    //$events = parent::getSubscribedEvents();
+    // $events = parent::getSubscribedEvents();
     // Come after field_ui, config_translation.
-    $events[RoutingEvents::ALTER] = array('onAlterRoutes', -210);
+    $events[RoutingEvents::ALTER] = ['onAlterRoutes', -210];
     return $events;
   }
 
diff --git a/web/modules/field_group/templates/field-group-html-element.html.twig b/web/modules/field_group/templates/field-group-html-element.html.twig
index 73072fcc0a503ef3accdc79004ecdc73e0f235ed..2b971773a1b47a0c4023b9d767b8ca72d0d7e37b 100644
--- a/web/modules/field_group/templates/field-group-html-element.html.twig
+++ b/web/modules/field_group/templates/field-group-html-element.html.twig
@@ -18,7 +18,7 @@
 
 <{{ wrapper_element }} {{ attributes }}>
   {% if title %}
-  <{{ title_element }}{% if collapsible %} class="field-group-toggler"{% endif %}>{{ title }}</{{ title_element }}>
+  <{{ title_element }}{{ title_attributes }}>{{ title }}</{{ title_element }}>
   {% endif %}
   {% if collapsible %}
   <div class="field-group-wrapper">
@@ -27,4 +27,4 @@
   {% if collapsible %}
   </div>
   {% endif %}
-</{{ wrapper_element }}>
\ No newline at end of file
+</{{ wrapper_element }}>
diff --git a/web/modules/field_group/templates/theme.inc b/web/modules/field_group/templates/theme.inc
index 2f0d20a989411c6963d33273ab79bd2d28399f79..048c956d18bcbda43d2c2fc29cc117554114d7f6 100644
--- a/web/modules/field_group/templates/theme.inc
+++ b/web/modules/field_group/templates/theme.inc
@@ -5,6 +5,8 @@
  * Preprocessors for fieldgroup elements.
  */
 
+use Drupal\Core\Template\Attribute;
+
 /**
  * Prepares variables for horizontal tabs templates.
  *
@@ -14,9 +16,8 @@
  *   An associative array containing:
  *   - element: An associative array containing the properties and children of
  *     the details element. Properties used: #children.
- *
  */
-function template_preprocess_horizontal_tabs(&$variables) {
+function template_preprocess_horizontal_tabs(array &$variables) {
   $element = $variables['element'];
   $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : '';
 }
@@ -30,9 +31,8 @@ function template_preprocess_horizontal_tabs(&$variables) {
  *   An associative array containing:
  *   - element: An associative array containing the properties and children of
  *     the accordion element. Properties used: #children.
- *
  */
-function template_preprocess_field_group_accordion(&$variables) {
+function template_preprocess_field_group_accordion(array &$variables) {
   $element = $variables['element'];
   $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : '';
 }
@@ -46,9 +46,8 @@ function template_preprocess_field_group_accordion(&$variables) {
  *   An associative array containing:
  *   - element: An associative array containing the properties and children of
  *     the accordion item element.
- *
  */
-function template_preprocess_field_group_accordion_item(&$variables) {
+function template_preprocess_field_group_accordion_item(array &$variables) {
 
   $element = $variables['element'];
 
@@ -61,7 +60,7 @@ function template_preprocess_field_group_accordion_item(&$variables) {
   }
 
   $variables['open'] = $element['#open'];
-  $variables['label_attributes'] = new \Drupal\Core\Template\Attribute();
+  $variables['label_attributes'] = new Attribute();
   $variables['children'] = (!empty($element['#children'])) ? $element['#children'] : '';
 
 }
@@ -75,15 +74,15 @@ function template_preprocess_field_group_accordion_item(&$variables) {
  *   An associative array containing:
  *   - element: An associative array containing the properties and children of
  *     the html element.
- *
  */
-function template_preprocess_field_group_html_element(&$variables) {
+function template_preprocess_field_group_html_element(array &$variables) {
 
   $element = $variables['element'];
 
   if (!empty($element['#title']) && !empty($element['#title_element'])) {
     $variables['title_element'] = $element['#title_element'];
     $variables['title'] = $element['#title'];
+    $variables['title_attributes'] = $element['#title_attributes'];
   }
 
   $variables['collapsible'] = (!empty($element['#effect']) && $element['#effect'] !== 'none');
diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
index 4113863e66716255e9603dcae02378f929d05a4b..cb1a2dd8c1f6671fcf34e799356242b31cbcba6b 100644
--- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
+++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
@@ -4,8 +4,9 @@ description: 'Test module for Field Group'
 package: 'Fields'
 type: module
 hidden: TRUE
-# Information added by Drupal.org packaging script on 2017-11-10
-version: '8.x-1.0'
+
+# Information added by Drupal.org packaging script on 2019-05-23
+version: '8.x-3.0-rc1'
 core: '8.x'
 project: 'field_group'
-datestamp: 1510352889
+datestamp: 1558647188
diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.module b/web/modules/field_group/tests/modules/field_group_test/field_group_test.module
index 629ed9bae660dd13c433c666fb4eeecd13697705..e17f80359ac5bca9df5083d0a4e3309444c06727 100644
--- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.module
+++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.module
@@ -1,20 +1,22 @@
 <?php
 
-use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Field\FieldDefinitionInterface;
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Session\AccountInterface;
-
 /**
  * @file
  * Fieldgroup test module.
  */
 
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Session\AccountInterface;
+
 /**
  * Implements hook_entity_field_access().
  */
-function field_group_test_entity_field_access($operation, FieldDefinitionInterface $field_definition,
-  AccountInterface $account, FieldItemListInterface $items = NULL) {
+function field_group_test_entity_field_access($operation,
+ FieldDefinitionInterface $field_definition,
+  AccountInterface $account,
+ FieldItemListInterface $items = NULL) {
 
   // Set access to false for field_no_access.
   if ($operation == 'view' && $field_definition->getName() == 'field_no_access') {
@@ -24,4 +26,3 @@ function field_group_test_entity_field_access($operation, FieldDefinitionInterfa
   return AccessResult::neutral();
 
 }
-
diff --git a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
index 5fc5da9ef12a6b8d672560507cbf305f0ed3df99..ce2e20d70389d477a6a3840da9c6074e83577772 100644
--- a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
+++ b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
@@ -53,21 +53,21 @@ public function setUp() {
       'administer node fields',
       'administer node form display',
       'administer node display',
-      'bypass node access'
+      'bypass node access',
     ]);
     $this->drupalLogin($admin_user);
 
     // Create content type, with underscores.
     $type_name = strtolower($this->randomMachineName(8)) . '_test';
-    $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
+    $type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]);
     $this->type = $type->id();
     /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
     $display = \Drupal::entityTypeManager()
       ->getStorage('entity_view_display')
-      ->load('node' . '.' . $type_name . '.' . 'default');
+      ->load('node.' . $type_name . '.default');
 
     // Create a node.
-    $node_values = array('type' => $type_name);
+    $node_values = ['type' => $type_name];
 
     // Create test fields.
     foreach (['field_test', 'field_test_2', 'field_no_access'] as $field_name) {
@@ -89,13 +89,13 @@ public function setUp() {
       $node_values[$field_name][0]['value'] = mt_rand(1, 127);
 
       // Set the field visible on the display object.
-      $display_options = array(
+      $display_options = [
         'label' => 'above',
         'type' => 'field_test_default',
-        'settings' => array(
+        'settings' => [
           'test_formatter_setting' => $this->randomMachineName(),
-        ),
-      );
+        ],
+      ];
       $display->setComponent($field_name, $display_options);
     }
 
@@ -108,63 +108,64 @@ public function setUp() {
    * Test field access for field groups.
    */
   public function testFieldAccess() {
-    $data = array(
+    $data = [
       'label' => 'Wrapper',
-      'children' => array(
+      'children' => [
         0 => 'field_no_access',
-      ),
+      ],
       'format_type' => 'html_element',
-      'format_settings' => array(
+      'format_settings' => [
         'element' => 'div',
         'id' => 'wrapper-id',
-      ),
-    );
+      ],
+    ];
 
     $this->createGroup('node', $this->type, 'view', 'default', $data);
     $this->drupalGet('node/' . $this->node->id());
 
     // Test if group is not shown.
-    $this->assertNoFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, t('Div that contains fields with no access is not shown.'));
+    $this->assertEmpty($this->xpath("//div[contains(@id, 'wrapper-id')]"), t('Div that contains fields with no access is not shown.'));
   }
 
   /**
    * Test the html element formatter.
    */
   public function testHtmlElement() {
-    $data = array(
+    $data = [
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test',
         1 => 'body',
-      ),
+      ],
       'label' => 'Link',
       'format_type' => 'html_element',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Link',
         'element' => 'div',
         'id' => 'wrapper-id',
         'classes' => 'test-class',
-      ),
-    );
+      ],
+    ];
     $group = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    //$groups = field_group_info_groups('node', 'article', 'view', 'default', TRUE);
+    // $groups = field_group_info_groups('node', 'article', 'view', 'default', TRUE);.
     $this->drupalGet('node/' . $this->node->id());
 
     // Test group ids and classes.
-    $this->assertFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, 'Wrapper id set on wrapper div');
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, 'Test class set on wrapper div, class="' . $group->group_name . ' test-class');
+    $this->assertTrue($this->xpath("//div[contains(@id, 'wrapper-id')]"), 'Wrapper id set on wrapper div');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class')]"), 'Test class set on wrapper div, class="' . $group->group_name . ' test-class');
 
     // Test group label.
-    $this->assertNoRaw('<h3><span>' . $data['label'] . '</span></h3>');
+    $this->assertSession()->responseNotContains('<h3><span>' . $data['label'] . '</span></h3>');
 
     // Set show label to true.
     $group->format_settings['show_label'] = TRUE;
     $group->format_settings['label_element'] = 'h3';
+    $group->format_settings['label_element_classes'] = 'my-label-class';
     field_group_group_save($group);
 
     $this->drupalGet('node/' . $this->node->id());
-    $this->assertRaw('<h3>' . $data['label'] . '</h3>');
+    $this->assertSession()->responseContains('<h3 class="my-label-class">' . $data['label'] . '</h3>');
 
     // Change to collapsible with blink effect.
     $group->format_settings['effect'] = 'blink';
@@ -172,175 +173,175 @@ public function testHtmlElement() {
     field_group_group_save($group);
 
     $this->drupalGet('node/' . $this->node->id());
-    $this->assertFieldByXPath("//div[contains(@class, 'speed-fast')]", NULL, 'Speed class is set');
-    $this->assertFieldByXPath("//div[contains(@class, 'effect-blink')]", NULL, 'Effect class is set');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'speed-fast')]"), 'Speed class is set');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'effect-blink')]"), 'Effect class is set');
   }
 
   /**
    * Test the fieldset formatter.
    */
   public function testFieldset() {
-    $data = array(
+    $data = [
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test',
         1 => 'body',
-      ),
+      ],
       'label' => 'Test Fieldset',
       'format_type' => 'fieldset',
-      'format_settings' => array(
+      'format_settings' => [
         'id' => 'fieldset-id',
         'classes' => 'test-class',
         'description' => 'test description',
-      ),
-    );
+      ],
+    ];
     $this->createGroup('node', $this->type, 'view', 'default', $data);
 
     $this->drupalGet('node/' . $this->node->id());
 
     // Test group ids and classes.
-    $this->assertFieldByXPath("//fieldset[contains(@id, 'fieldset-id')]", NULL, 'Correct id set on the fieldset');
-    $this->assertFieldByXPath("//fieldset[contains(@class, 'test-class')]", NULL, 'Test class set on the fieldset');
+    $this->assertTrue($this->xpath("//fieldset[contains(@id, 'fieldset-id')]"), 'Correct id set on the fieldset');
+    $this->assertTrue($this->xpath("//fieldset[contains(@class, 'test-class')]"), 'Test class set on the fieldset');
   }
 
   /**
    * Test the tabs formatter.
    */
   public function testTabs() {
-    $data = array(
+    $data = [
       'label' => 'Tab 1',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test',
-      ),
+      ],
       'format_type' => 'tab',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Tab 1',
         'classes' => 'test-class',
         'description' => '',
         'formatter' => 'open',
-      ),
-    );
+      ],
+    ];
     $first_tab = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $data = array(
+    $data = [
       'label' => 'Tab 2',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test_2',
-      ),
+      ],
       'format_type' => 'tab',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Tab 1',
         'classes' => 'test-class-2',
         'description' => 'description of second tab',
         'formatter' => 'closed',
-      ),
-    );
+      ],
+    ];
     $second_tab = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $data = array(
+    $data = [
       'label' => 'Tabs',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => $first_tab->group_name,
         1 => $second_tab->group_name,
-      ),
+      ],
       'format_type' => 'tabs',
-      'format_settings' => array(
+      'format_settings' => [
         'direction' => 'vertical',
         'label' => 'Tab 1',
         'classes' => 'test-class-wrapper',
-      ),
-    );
+      ],
+    ];
     $tabs_group = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
     $this->drupalGet('node/' . $this->node->id());
 
     // Test properties.
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, 'Test class set on tabs wrapper');
-    $this->assertFieldByXPath("//details[contains(@class, 'test-class-2')]", NULL, 'Test class set on second tab');
-    $this->assertRaw('<div class="details-description">description of second tab</div>');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]"), 'Test class set on tabs wrapper');
+    $this->assertTrue($this->xpath("//details[contains(@class, 'test-class-2')]"), 'Test class set on second tab');
+    $this->assertSession()->responseContains('<div class="details-description">description of second tab</div>');
 
     // Test if correctly nested.
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class')]", NULL, 'First tab is displayed as child of the wrapper.');
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class-2')]", NULL, 'Second tab is displayed as child of the wrapper.');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class')]"), 'First tab is displayed as child of the wrapper.');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//details[contains(@class, 'test-class-2')]"), 'Second tab is displayed as child of the wrapper.');
 
     // Test if it's a vertical tab.
-    $this->assertFieldByXPath('//div[@data-vertical-tabs-panes=""]', NULL, 'Tabs are shown vertical.');
+    $this->assertTrue($this->xpath('//div[@data-vertical-tabs-panes=""]'), 'Tabs are shown vertical.');
 
-    // Switch to horizontal
+    // Switch to horizontal.
     $tabs_group->format_settings['direction'] = 'horizontal';
     field_group_group_save($tabs_group);
 
     $this->drupalGet('node/' . $this->node->id());
 
     // Test if it's a horizontal tab.
-    $this->assertFieldByXPath('//div[@data-horizontal-tabs-panes=""]', NULL, 'Tabs are shown horizontal.');
+    $this->assertTrue($this->xpath('//div[@data-horizontal-tabs-panes=""]'), 'Tabs are shown horizontal.');
   }
 
   /**
    * Test the accordion formatter.
    */
   public function testAccordion() {
-    $data = array(
+    $data = [
       'label' => 'Accordion item 1',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test',
-      ),
+      ],
       'format_type' => 'accordion_item',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Accordion item 1',
         'classes' => 'test-class',
         'formatter' => 'closed',
-      ),
-    );
+      ],
+    ];
     $first_item = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $data = array(
+    $data = [
       'label' => 'Accordion item 2',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => 'field_test_2',
-      ),
+      ],
       'format_type' => 'accordion_item',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Tab 2',
         'classes' => 'test-class-2',
         'formatter' => 'open',
-      ),
-    );
+      ],
+    ];
     $second_item = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $data = array(
+    $data = [
       'label' => 'Accordion',
       'weight' => '1',
-      'children' => array(
+      'children' => [
         0 => $first_item->group_name,
         1 => $second_item->group_name,
-      ),
+      ],
       'format_type' => 'accordion',
-      'format_settings' => array(
+      'format_settings' => [
         'label' => 'Tab 1',
         'classes' => 'test-class-wrapper',
-        'effect' => 'bounceslide'
-      ),
-    );
+        'effect' => 'bounceslide',
+      ],
+    ];
     $this->createGroup('node', $this->type, 'view', 'default', $data);
 
     $this->drupalGet('node/' . $this->node->id());
 
     // Test properties.
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, 'Test class set on tabs wrapper');
-    $this->assertFieldByXPath("//div[contains(@class, 'effect-bounceslide')]", NULL, 'Correct effect is set on the accordion');
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, 'Accordion item with test-class is shown');
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-2')]", NULL, 'Accordion item with test-class-2 is shown');
-    $this->assertFieldByXPath("//h3[contains(@class, 'field-group-accordion-active')]", NULL, 'Accordion item 2 was set active');
-
-    // Test if correctly nested
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]", NULL, 'First item is displayed as child of the wrapper.');
-    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]", NULL, 'Second item is displayed as child of the wrapper.');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]"), 'Test class set on tabs wrapper');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'effect-bounceslide')]"), 'Correct effect is set on the accordion');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class')]"), 'Accordion item with test-class is shown');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-2')]"), 'Accordion item with test-class-2 is shown');
+    $this->assertTrue($this->xpath("//h3[contains(@class, 'field-group-accordion-active')]"), 'Accordion item 2 was set active');
+
+    // Test if correctly nested.
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]"), 'First item is displayed as child of the wrapper.');
+    $this->assertTrue($this->xpath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]"), 'Second item is displayed as child of the wrapper.');
   }
 
 }
diff --git a/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php b/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php
index c622a10be2e40f41c87a43ecb011b2d3bc9cbc52..563ec92cd148c89925113e002f775cb169a95d18 100644
--- a/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php
+++ b/web/modules/field_group/tests/src/Functional/FieldGroupTestTrait.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\Tests\field_group\Functional;
 
-use Drupal\Component\Utility\Unicode;
+use Drupal;
 
 /**
  * Provides common functionality for the FieldGroup test classes.
@@ -15,7 +15,7 @@ trait FieldGroupTestTrait {
    * @param string $entity_type
    *   The entity type as string.
    * @param string $bundle
-   *   The bundle of the enity type
+   *   The bundle of the enity type.
    * @param string $context
    *   The context for the group.
    * @param string $mode
@@ -29,27 +29,27 @@ trait FieldGroupTestTrait {
   protected function createGroup($entity_type, $bundle, $context, $mode, array $data) {
 
     if (!isset($data['format_settings'])) {
-      $data['format_settings'] = array();
+      $data['format_settings'] = [];
     }
 
-    $data['format_settings'] += _field_group_get_default_formatter_settings($data['format_type'], $context);
+    $data['format_settings'] += Drupal::service('plugin.manager.field_group.formatters')->getDefaultSettings($data['format_type'], $context);
 
-    $group_name = 'group_' . Unicode::strtolower($this->randomMachineName());
+    $group_name = 'group_' . mb_strtolower($this->randomMachineName());
 
-    $field_group = (object) array(
+    $field_group = (object) [
       'group_name' => $group_name,
       'entity_type' => $entity_type,
       'bundle' => $bundle,
       'mode' => $mode,
       'context' => $context,
-      'children' => isset($data['children']) ? $data['children'] : array(),
+      'children' => isset($data['children']) ? $data['children'] : [],
       'parent_name' => isset($data['parent']) ? $data['parent'] : '',
       'weight' => isset($data['weight']) ? $data['weight'] : 0,
       'label' => isset($data['label']) ? $data['label'] : $this->randomString(8),
       'format_type' => $data['format_type'],
       'format_settings' => $data['format_settings'],
       'region' => 'content',
-    );
+    ];
 
     field_group_group_save($field_group);
 
diff --git a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
index 2beae972bf2c58bf2f3b1bf87e9befaf7e3b15c0..bcb76009846248a894cbc7bfb4273e2d39f14e75 100644
--- a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
+++ b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
@@ -21,7 +21,7 @@ class FieldGroupWithoutFieldUiTest extends BrowserTestBase {
    * Test that local actions show up without field ui enabled.
    */
   public function testLocalActions() {
-    // Local actions of field_group should not depend on field_ui
+    // Local actions of field_group should not depend on field_ui.
     // @see https://www.drupal.org/node/2719569
     $this->placeBlock('local_actions_block', ['id' => 'local_actions_block']);
     $this->drupalGet(Url::fromRoute('user.login'));
diff --git a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
index e89ee4600f0889641a59ece38bdc8e6f7e819fb5..f05c56d1c23ef58265e1d68899fd9a2d19452450 100644
--- a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
+++ b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\Tests\field_group\Functional;
 
-use Drupal\Component\Utility\Unicode;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -17,7 +16,7 @@ class ManageDisplayTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = array('node', 'field_ui', 'field_group');
+  public static $modules = ['node', 'field_ui', 'field_group'];
 
   /**
    * Content type id.
@@ -58,15 +57,15 @@ public function setUp() {
   public function testCreateGroup() {
     // Create random group name.
     $group_label = $this->randomString(8);
-    $group_name_input = Unicode::strtolower($this->randomMachineName());
+    $group_name_input = mb_strtolower($this->randomMachineName());
     $group_name = 'group_' . $group_name_input;
     $group_formatter = 'details';
 
     // Setup new group.
-    $group = array(
+    $group = [
       'group_formatter' => $group_formatter,
       'label' => $group_label,
-    );
+    ];
 
     $add_form_display = 'admin/structure/types/manage/' . $this->type . '/form-display/add-group';
     $this->drupalPostForm($add_form_display, $group, 'Save and continue');
@@ -79,7 +78,7 @@ public function testCreateGroup() {
     $this->drupalPostForm($add_form_display, $group, 'Save and continue');
     $this->drupalPostForm(NULL, [], 'Create group');
 
-    $this->assertSession()->responseContains(t('New group %label successfully created.', array('%label' => $group_label)));
+    $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label]));
 
     // Test if group is in the $groups array.
     $this->group = field_group_load_field_group($group_name, 'node', $this->type, 'form', 'default');
@@ -89,7 +88,7 @@ public function testCreateGroup() {
     $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/add-group', $group, 'Save and continue');
     $this->drupalPostForm(NULL, [], 'Create group');
 
-    $this->assertSession()->responseContains(t('New group %label successfully created.', array('%label' => $group_label)));
+    $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label]));
 
     // Test if group is in the $groups array.
     $loaded_group = field_group_load_field_group($group_name, 'node', $this->type, 'view', 'default');
@@ -100,15 +99,15 @@ public function testCreateGroup() {
    * Delete a group.
    */
   public function testDeleteGroup() {
-    $data = array(
+    $data = [
       'format_type' => 'fieldset',
       'label' => 'testing',
-    );
+    ];
 
     $group = $this->createGroup('node', $this->type, 'form', 'default', $data);
 
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete', array(), 'Delete');
-    $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', array('%label' => $group->label, '%type' => $this->type)));
+    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete', [], 'Delete');
+    $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type]));
 
     // Test that group is not in the $groups array.
     \Drupal::entityTypeManager()
@@ -117,15 +116,15 @@ public function testDeleteGroup() {
     $loaded_group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default');
     $this->assertNull($loaded_group, 'Group not found after deleting');
 
-    $data = array(
+    $data = [
       'format_type' => 'fieldset',
       'label' => 'testing',
-    );
+    ];
 
     $group = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete', array(), t('Delete'));
-    $this->assertRaw(t('The group %label has been deleted from the %type content type.', array('%label' => $group->label, '%type' => $this->type)));
+    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete', [], t('Delete'));
+    $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type]));
 
     // Test that group is not in the $groups array.
     \Drupal::entityTypeManager()
@@ -139,20 +138,20 @@ public function testDeleteGroup() {
    * Nest a field underneath a group.
    */
   public function testNestField() {
-    $data = array(
+    $data = [
       'format_type' => 'fieldset',
-    );
+    ];
 
     $group = $this->createGroup('node', $this->type, 'form', 'default', $data);
 
-    $edit = array(
+    $edit = [
       'fields[body][parent]' => $group->group_name,
-    );
+    ];
     $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display', $edit, 'Save');
-    $this->assertRaw('Your settings have been saved.');
+    $this->assertSession()->responseContains('Your settings have been saved.');
 
     $group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default');
-    $this->assertTrue(in_array('body', $group->children), t('Body is a child of %group', array('%group' => $group->group_name)));
+    $this->assertTrue(in_array('body', $group->children), t('Body is a child of %group', ['%group' => $group->group_name]));
   }
 
 }
diff --git a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
index 75d74ea834348921f1d0ff43eaf1ed14fec12e73..e237c73f143a0ea581c84400e5f1b1c416fd0c4f 100644
--- a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
+++ b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
@@ -2,9 +2,8 @@
 
 namespace Drupal\Tests\field_group\FunctionalJavascript;
 
-use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\node\Entity\NodeType;
 use Drupal\Tests\field_group\Functional\FieldGroupTestTrait;
 
@@ -13,7 +12,7 @@
  *
  * @group field_group
  */
-class FieldGroupUiTest extends JavascriptTestBase {
+class FieldGroupUiTest extends WebDriverTestBase {
 
   use FieldGroupTestTrait;
 
@@ -22,13 +21,18 @@ class FieldGroupUiTest extends JavascriptTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'field_ui', 'field_group');
+  public static $modules = ['node', 'field_ui', 'field_group'];
 
   /**
+   * The current tested node type
+   *
    * @var string
    */
   protected $nodeType;
 
+  /**
+   * {@inheritdoc}
+   */
   public function setUp() {
     parent::setUp();
 
@@ -44,7 +48,7 @@ public function setUp() {
     $this->drupalLogin($admin_user);
 
     // Create content type, with underscores.
-    $type_name =  Unicode::strtolower($this->randomMachineName(8)) . '_test';
+    $type_name = mb_strtolower($this->randomMachineName(8)) . '_test';
     $type = NodeType::create([
       'name' => $type_name,
       'type' => $type_name,
@@ -58,18 +62,18 @@ public function setUp() {
    */
   public function testCreateAndEdit() {
     foreach (['test_1', 'test_2'] as $name) {
-      $group = array(
+      $group = [
         'group_formatter' => 'details',
         'label' => 'Test 1',
         'group_name' => $name,
-      );
+      ];
 
       // Add new group on the 'Manage form display' page.
       $this->drupalPostForm('admin/structure/types/manage/' . $this->nodeType . '/form-display/add-group', $group, 'Save and continue');
       $this->drupalPostForm(NULL, [], 'Create group');
     }
 
-    // Update title in group 1
+    // Update title in group 1.
     $page = $this->getSession()->getPage();
     $page->pressButton('group_test_1_group_settings_edit');
     $this->assertSession()->assertWaitOnAjaxRequest();
@@ -77,14 +81,14 @@ public function testCreateAndEdit() {
     $page->pressButton('Update');
     $this->assertSession()->assertWaitOnAjaxRequest();
 
-    // Update title in group 2
+    // Update title in group 2.
     $page->pressButton('group_test_2_group_settings_edit');
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->fillField('fields[group_test_2][settings_edit_form][settings][label]', 'Test 2 - Update');
     $page->pressButton('Update');
     $this->assertSession()->assertWaitOnAjaxRequest();
 
-    // Open group 1 again
+    // Open group 1 again.
     $page->pressButton('group_test_1_group_settings_edit');
     $this->assertSession()->assertWaitOnAjaxRequest();
     $this->assertSession()->fieldValueEquals('fields[group_test_1][settings_edit_form][settings][label]', 'Test 1 - Update');