diff --git a/composer.json b/composer.json
index ecd8c6bb2b4a2ce3de42e80f191dc647cb569357..4eacbf169bbb24dbadfb4973f555eae7ce6c7791 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,8 @@
             "email": "christian.wiedemann@key-tec.de"
         }
     ],
-    "require": {
-      "drupal/ui_patterns": "^2.0"
+    "require-dev": {
+      "drupal/ui_patterns": "2.0.x-dev",
+      "drupal/field_group": "^3.0"
     }
 }
diff --git a/modules/ui_patterns_ui_fieldgroups/src/Element/DisplayFormFieldGroup.php b/modules/ui_patterns_ui_fieldgroups/src/Element/DisplayFormFieldGroup.php
new file mode 100644
index 0000000000000000000000000000000000000000..326bb65f2bb1d84910f4b9b1a646e44b8a3d8d33
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/src/Element/DisplayFormFieldGroup.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns_ui_fieldgroups\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Security\TrustedCallbackInterface;
+use Drupal\Core\Theme\ComponentPluginManager;
+
+/**
+ * Our additions to the SDC render element.
+ */
+class DisplayFormFieldGroup implements TrustedCallbackInterface {
+
+  /**
+   * Constructs a ComponentElementAlter.
+   */
+  public function __construct(protected ComponentPluginManager $componentPluginManager) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function trustedCallbacks() {
+    return ['process'];
+
+  }
+
+  /**
+   * Alter SDC component element.
+   *
+   * The ::normalizeProps() methods logic has been moved to
+   * TwigExtension::normalizeProps() in order to be executed also when
+   * components are loaded from Twig include or embed.
+   */
+  public static function process(array $element, FormStateInterface $form_state): array {
+    /** @var \Drupal\ui_patterns_ui\Entity\ComponentFormDisplay $display */
+    $display = $element['#display'] ?? NULL;
+    if ($display === NULL) {
+      return $element;
+    }
+
+    $display_options = $display->getPropSlotOptions();
+    $groups = ui_patterns_ui_fieldgroups_info($display);
+    foreach ($display_options as $display_option_id => $option) {
+      if (isset($groups[$display_option_id])) {
+        $element[$display_option_id] = [];
+        $group = $groups[$display_option_id];
+        $complete_form = $form_state->getCompleteForm();
+        field_group_field_group_form_process($element[$display_option_id], $group, $complete_form);
+      }
+      if (!empty($option['parent'])) {
+        $parents = $element['#parents'];
+        $parents[] = $option['parent'];
+        if (str_starts_with($display_option_id, 'group_')) {
+          $element[$display_option_id]['#group'] = $option['parent'];
+        }
+        else {
+          $element[$display_option_id]['#group'] = implode('][', $parents);
+        }
+      }
+    }
+
+    return $element;
+  }
+
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/src/FieldGroupFormTrait.php b/modules/ui_patterns_ui_fieldgroups/src/FieldGroupFormTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..208b704df75eaf436da1b654f316c6576824b0fc
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/src/FieldGroupFormTrait.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns_ui_fieldgroups;
+
+use Drupal\ui_patterns_ui\ComponentFormDisplayInterface;
+use Drupal\ui_patterns_ui\Entity\ComponentFormDisplay;
+
+/**
+ * Trait for plugins (sources and prop types) handling attributes.
+ */
+trait FieldGroupFormTrait {
+
+  /**
+   * Returns the current display.
+   */
+  protected function getDisplay():?ComponentFormDisplayInterface {
+    $component_id = \Drupal::routeMatch()->getParameter('component_id');
+    $form_mode_name = \Drupal::routeMatch()->getParameter('form_mode_name');
+    return ComponentFormDisplay::loadByFormMode($component_id, $form_mode_name);
+  }
+
+  /**
+   * Returns the current group.
+   */
+  public function getGroup(): mixed {
+    $group_id = \Drupal::routeMatch()->getParameter('group_id');
+    $groups = ui_patterns_ui_fieldgroups_info($this->getDisplay());
+    return $groups[$group_id] ?? NULL;
+  }
+
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupAddForm.php b/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupAddForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..8cb3bde21b0e1fab3b087dcdac0a7f58ab41cec2
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupAddForm.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace Drupal\ui_patterns_ui_fieldgroups\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\field_group\Form\FieldGroupAddForm as BaseFieldGroupAddForm;
+use Drupal\ui_patterns_ui\Entity\ComponentFormDisplay;
+use Drupal\ui_patterns_ui_fieldgroups\FieldGroupFormTrait;
+
+/**
+ * Provides a form for adding a fieldgroup to a bundle.
+ */
+class FieldGroupAddForm extends BaseFieldGroupAddForm {
+  use FieldGroupFormTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, mixed $entity_type_id = NULL, mixed $bundle = NULL, mixed $context = NULL) {
+    $group_id = $this->getRouteMatch()->getParameter('group_id');
+    $this->context = 'form';
+    if ($group_id !== NULL) {
+      return $this->buildEditConfigurationForm($form, $form_state);
+    }
+    else {
+      return parent::buildForm($form, $form_state, $entity_type_id, $bundle, 'form');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildEditConfigurationForm(array &$form, FormStateInterface $form_state): array {
+    $group = $this->getGroup();
+    $manager = $this->fieldGroupFormatterPluginManager;
+    $plugin = $manager->getInstance([
+      'format_type' => $group->format_type,
+      'configuration' => [
+        'label' => $group->label,
+        'settings' => $group->format_settings,
+      ],
+      'group' => $group,
+    ]);
+    $form['format_settings'] = [
+      '#type' => 'container',
+      '#tree' => TRUE,
+    ];
+
+    $form['format_settings'] += $plugin->settingsForm();
+
+    $form['actions'] = ['#type' => 'actions'];
+    $form['actions']['submit'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Update group'),
+      '#button_type' => 'primary',
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
+    $group_id = $this->getRouteMatch()->getParameter('group_id');
+    $group_name = $group_id ?? $form_state->get('group_name');
+    if ($form_state->get('step') == 'formatter') {
+      $form_state->set('step', 'configuration');
+      $form_state->set('group_label', $form_state->getValue('label'));
+      $form_state->set('group_name', $form_state->getValue('group_name'));
+      $form_state->set('group_formatter', $form_state->getValue('group_formatter'));
+      $form_state->setRebuild();
+    }
+    else {
+
+      if ($group_id === NULL) {
+        $new_group = (object) [
+          'group_name' => $group_name,
+          'context' => 'form',
+          'children' => [],
+          'parent_name' => '',
+          'weight' => 20,
+          'format_type' => $form_state->get('group_formatter'),
+          'region' => 'hidden',
+        ];
+      }
+      else {
+        $new_group = $this->getGroup();
+      }
+
+      $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 += $this->fieldGroupFormatterPluginManager->getDefaultSettings($form_state->get('group_formatter'), $this->context);
+
+      $data = (array) $new_group;
+      unset($data['group_name'], $data['entity_type'], $data['bundle'], $data['mode'], $data['form'], $data['context']);
+      $form_mode_name = $this->getRouteMatch()->getParameter('form_mode_name');
+      $component_id = $this->getRouteMatch()->getParameter('component_id');
+      $display = ComponentFormDisplay::loadByFormMode($component_id, $form_mode_name);
+      $display->setThirdPartySetting('ui_patterns_ui_fieldgroups', $new_group->group_name, $data);
+      $display->save();
+      // 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;
+      $this->messenger->addMessage($this->t('New group %label successfully created.', ['%label' => $new_group->label]));
+
+      $form_state->setRedirectUrl($display->toUrl('edit-form'));
+      $this->cacheBackend->invalidate('field_groups');
+
+    }
+
+  }
+
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupDeleteForm.php b/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupDeleteForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..aa1ea6888c52e9c4ece83b8755d957784526d8a9
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/src/Form/FieldGroupDeleteForm.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\ui_patterns_ui_fieldgroups\Form;
+
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\ui_patterns_ui_fieldgroups\FieldGroupFormTrait;
+
+/**
+ * Provides a form for removing a fieldgroup from a component.
+ */
+class FieldGroupDeleteForm extends ConfirmFormBase {
+  use FieldGroupFormTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return $this->getDisplay()->toUrl('edit-form');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
+    $display = $this->getDisplay();
+    $group_id = $this->getRouteMatch()->getParameter('group_id');
+    $display->unsetThirdPartySetting('ui_patterns_ui_fieldgroups', $group_id);
+    $display->removePropSlotOption($group_id);
+    foreach ($display->getPropSlotOptions() as $prop_id => $options) {
+      if ($options['parent'] === $group_id) {
+        $options['parent'] = '';
+        $display->setPropSlotOptions($prop_id, $options);
+      }
+    }
+    $display->save();
+    $form_state->setRedirectUrl($this->getCancelUrl());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    $group = $this->getGroup();
+    return $this->t('Are you sure you want to delete the group %group?', ['%group' => $group->label ?? '']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'ui_patterns_ui_fieldgroups_delete_form';
+  }
+
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/src/Plugin/Derivative/UiPatternsUiFieldgroupLocalAction.php b/modules/ui_patterns_ui_fieldgroups/src/Plugin/Derivative/UiPatternsUiFieldgroupLocalAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..56fc8a013f275d14104477edf9dec2dd91e509d5
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/src/Plugin/Derivative/UiPatternsUiFieldgroupLocalAction.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Drupal\ui_patterns_ui_fieldgroups\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Theme\ComponentPluginManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides local action definitions for all component forms.
+ */
+class UiPatternsUiFieldgroupLocalAction extends DeriverBase implements ContainerDeriverInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * Constructs a UiPatternsUiLocalAction object.
+   */
+  public function __construct(protected RouteProviderInterface $routeProvider, protected ComponentPluginManager $componentPluginManager, protected EntityTypeManagerInterface $entityTypeManager) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('router.route_provider'),
+      $container->get('plugin.manager.sdc'),
+      $container->get('entity_type.manager'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $this->derivatives = [];
+
+    /** @var \Drupal\ui_patterns_ui\Entity\ComponentFormDisplay[] $displays */
+    $displays = $this->entityTypeManager->getStorage('component_form_display')->loadMultiple();
+    foreach ($displays as $display) {
+      $this->derivatives["component_form_display.{$display->getComponentId()}.fieldgroup.add"] = [
+        'route_name' => "entity.component_form_display.add_group",
+        'title' => $this->t('Add Fieldgroup'),
+        'appears_on' => ["entity.component_form_display.{$display->getComponentId()}.edit_form"],
+        'parameters' => [
+          'form_mode_name' => $display->getFormModeName(),
+          'component_id' => $display->getComponentId(),
+        ],
+      ];
+    }
+
+    foreach ($this->derivatives as &$entry) {
+      $entry += $base_plugin_definition;
+    }
+
+    return $this->derivatives;
+  }
+
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.info.yml b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a74a85e71df053eacbb351282063762254cc3f8d
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.info.yml
@@ -0,0 +1,9 @@
+name: UI Patterns UI fieldgroups
+type: module
+description: Configure patterns with fieldgroups
+package: User interface
+core_version_requirement: ^10.3 || ^11
+dependencies:
+  - ui_patterns:ui_patterns (>=2.0)
+  - ui_patterns:ui_patterns_ui (>=2.0)
+  - field_group:field_group
diff --git a/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.links.action.yml b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.links.action.yml
new file mode 100644
index 0000000000000000000000000000000000000000..44f64583853560b81922cd1a96e31f6c9ae7743b
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.links.action.yml
@@ -0,0 +1,3 @@
+ui_patterns_ui_fieldgroups.fieldgroups:
+  class: \Drupal\Core\Menu\LocalActionDefault
+  deriver: \Drupal\ui_patterns_ui_fieldgroups\Plugin\Derivative\UiPatternsUiFieldgroupLocalAction
diff --git a/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.module b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.module
new file mode 100644
index 0000000000000000000000000000000000000000..42bb3c8ec8b3ab30cc6ab46e58e84c82d5a33982
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.module
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @file
+ * Contains ui_patterns_ui_fieldgroups.module.
+ */
+
+use Drupal\Core\Url;
+use Drupal\ui_patterns_ui\ComponentFormDisplayInterface;
+use Drupal\Core\Link;
+use Drupal\ui_patterns_ui_fieldgroups\Element\DisplayFormFieldGroup;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Implements hook_component_form_display_groups().
+ */
+function ui_patterns_ui_fieldgroups_component_form_display_groups(ComponentFormDisplayInterface $display): array {
+  return $display->getThirdPartySettings('ui_patterns_ui_fieldgroups');
+}
+
+/**
+ * Implements hook_element_info_alter().
+ */
+function ui_patterns_ui_fieldgroups_element_info_alter(array &$types): void {
+  if (isset($types['uip_display_form'])) {
+    $types['uip_display_form']['#process'][] = [DisplayFormFieldGroup::class, 'process'];
+  }
+
+}
+
+/**
+ * Build group objects.
+ *
+ * @param \Drupal\ui_patterns_ui\ComponentFormDisplayInterface $display
+ *   The component display.
+ *
+ * @return mixed
+ *   Info array.
+ */
+function ui_patterns_ui_fieldgroups_info(ComponentFormDisplayInterface $display) {
+  $data = $display->getThirdPartySettings('ui_patterns_ui_fieldgroups');
+  $groups = [];
+  if (isset($data) && is_array($data)) {
+    foreach ($data as $group_name => $definition) {
+      $definition += [
+        'group_name' => $group_name,
+        'context' => 'form',
+      ];
+      $groups[$group_name] = (object) $definition;
+    }
+  }
+  $options = $display->getPropSlotOptions();
+  foreach ($options as $group_name => $display_option) {
+    if (isset($groups[$group_name])) {
+      $group = $groups[$group_name];
+      $group->region = $display_option['region'];
+      $group->mode = 'form';
+      $group->entity_type = NULL;
+      $group->bundle = NULL;
+      $group->parent = $display_option['parent'] ?? NULL;
+    }
+
+    if (isset($groups[$display_option['parent']])) {
+      $parent_group = $groups[$display_option['parent']];
+      if (!isset($parent_group->children)) {
+        $parent_group->children = [];
+      }
+      $parent_group->children[] = $group_name;
+    }
+
+  }
+  return $groups;
+}
+
+/**
+ * Implements hook_component_form_display_group_row_alter().
+ */
+function ui_patterns_ui_fieldgroups_component_form_display_group_row_alter(array &$row, ComponentFormDisplayInterface $display, array $group): void {
+  $row['human_name']['#markup'] = $group['label'];
+  $row['settings_edit'] = [
+    '#type' => 'link',
+    '#title' => ['#markup' => '<img src="/core/misc/icons/787878/cog.svg"/>'],
+    '#url' => Url::fromRoute('entity.component_form_display.edit_group',
+      [
+        'component_id' => $display->getComponentId(),
+        'form_mode_name' => $display->getFormModeName(),
+        'group_id' => $group['id'],
+      ]),
+    '#src' => 'core/misc/icons/787878/cog.svg',
+    '#attributes' => [
+      'class' => ['field-plugin-settings-edit'],
+      'alt' => t('Edit'),
+    ],
+    '#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
+    '#suffix' => '</div>',
+  ];
+  $delete_route = Url::fromRoute('entity.component_form_display.delete_group',
+    [
+      'component_id' => $display->getComponentId(),
+      'form_mode_name' => $display->getFormModeName(),
+      'group_id' => $group['id'],
+    ]);
+  $row['settings_edit']['#suffix'] .= Link::fromTextAndUrl(t('delete'), $delete_route)->toString();
+
+}
+
+/**
+ * Implements hook_form_component_form_display_edit_form_alter().
+ */
+function ui_patterns_ui_fieldgroups_form_component_form_display_edit_form_alter(array &$form, FormStateInterface $form_state): void {
+  $form['#attached']['library'][] = 'field_group/field_ui';
+}
diff --git a/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.routing.yml b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.routing.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2a6d154a19a2a931b69b252199e1962962134e9b
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.routing.yml
@@ -0,0 +1,30 @@
+entity.component_form_display.add_group:
+  path: '/admin/structure/component/{component_id}/form-display/{form_mode_name}/add-group'
+  defaults:
+    entity_type_id: 'component_form_display'
+    context: form
+    _form: \Drupal\ui_patterns_ui_fieldgroups\Form\FieldGroupAddForm
+    _title: 'Add field group'
+  requirements:
+    _permission: 'administer component_form_display'
+
+entity.component_form_display.edit_group:
+  path: '/admin/structure/component/{component_id}/form-display/{form_mode_name}/{group_id}/edit-group'
+  defaults:
+    entity_type_id: 'component_form_display'
+    context: form
+    _form: \Drupal\ui_patterns_ui_fieldgroups\Form\FieldGroupAddForm
+    _title: 'Edit field group'
+  requirements:
+    _permission: 'administer component_form_display'
+
+
+entity.component_form_display.delete_group:
+  path: '/admin/structure/component/{component_id}/form-display/{form_mode_name}/{group_id}/delete-group'
+  defaults:
+    entity_type_id: 'component_form_display'
+    context: form
+    _form: \Drupal\ui_patterns_ui_fieldgroups\Form\FieldGroupDeleteForm
+    _title: 'Edit field group'
+  requirements:
+    _permission: 'administer component_form_display'
diff --git a/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.services.yml b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.services.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f703ccb4b72e06c7d2be1c030cbb5a9b9554e5e1
--- /dev/null
+++ b/modules/ui_patterns_ui_fieldgroups/ui_patterns_ui_fieldgroups.services.yml
@@ -0,0 +1,5 @@
+services:
+  ui_patterns_ui_fieldgroups.display_forms_alter:
+    class: Drupal\ui_patterns_ui_fieldgroups\Element\DisplayFormFieldGroup
+    arguments:
+      - "@plugin.manager.sdc"