diff --git a/js/layout-paragraphs-widget.js b/js/layout-paragraphs-widget.js
index d5eacb61fe84e7d3fd6050dd4b2c998a3290875b..2bd20e739c91654607a43d34c64d57812ed9f471 100644
--- a/js/layout-paragraphs-widget.js
+++ b/js/layout-paragraphs-widget.js
@@ -43,6 +43,29 @@
   ) => {
     setLoaded($(response.data.id));
   };
+  /**
+   * Ajax Command to insert or update a paragraph element.
+   * @param {object} ajax The ajax object.
+   * @param {object} response The response object.
+   */
+  Drupal.AjaxCommands.prototype.layoutParagraphsInsert = (ajax, response) => {
+    const { settings, content } = response;
+    const weight = Math.floor(settings.weight);
+    const $container = settings.parent_selector
+      ? $(settings.parent_selector, settings.wrapper_selector)
+      : $(".active-items", settings.wrapper_selector);
+    const $sibling = $container.find(
+      `.layout-paragraphs-weight option[value="${weight}"]:selected`
+    );
+
+    if ($(settings.selector, settings.wrapper_selector).length) {
+      $(settings.selector, settings.wrapper_selector).replaceWith(content);
+    } else if ($sibling.length) {
+      $sibling.closest(".layout-paragraphs-item").after(content);
+    } else {
+      $container.prepend(content);
+    }
+  };
   /**
    * The main layout-paragraphs Widget behavior.
    */
@@ -210,16 +233,6 @@
         $(item).addClass("dragula-enabled");
         // Turn on drag and drop if dragula function exists.
         if (typeof dragula !== "undefined") {
-          // Add layout handles.
-          $(".layout-paragraphs-item").each(
-            (layoutParagraphsItemIndex, layoutParagraphsItem) => {
-              $('<div class="layout-controls">')
-                .append($('<div class="layout-handle">'))
-                .append($('<div class="layout-up">').click(moveUp))
-                .append($('<div class="layout-down">').click(moveDown))
-                .prependTo(layoutParagraphsItem);
-            }
-          );
           const items = $(
             ".active-items, .layout-paragraphs-layout-wrapper, .layout-paragraphs-layout-region, .layout-paragraphs-disabled-items__items",
             item
@@ -435,9 +448,10 @@
       }
       /**
        * Enhances the radio button select for choosing a layout.
+       * @param {Object} layoutList The list of layout items.
        */
-      function enhanceRadioSelect() {
-        const $layoutRadioItem = $(".layout-select--list-item");
+      function enhanceRadioSelect(layoutList) {
+        const $layoutRadioItem = $(".layout-select--list-item", layoutList);
         $layoutRadioItem.click(e => {
           const $radioItem = $(e.currentTarget);
           const $layoutParagraphsField = $radioItem.closest(
@@ -581,68 +595,17 @@
           });
         });
       /**
-       * Load entity form in dialog.
+       * Add drag/drop/move controls.
        */
-      $(".layout-paragraphs-field .layout-paragraphs-form", context)
-        .once("layout-paragraphs-dialog")
-        .each((index, layoutParagraphsForm) => {
-          const buttons = [];
-          const $layoutParagraphsForm = $(layoutParagraphsForm);
-          $(
-            '.layout-paragraphs-item-form-actions input[type="submit"]',
-            layoutParagraphsForm
-          ).each((btnIndex, btn) => {
-            buttons.push({
-              text: btn.value,
-              class: btn.className,
-              click() {
-                if (
-                  isLoading(
-                    $layoutParagraphsForm.closest(".layout-paragraphs-field")
-                  )
-                ) {
-                  return false;
-                }
-                setLoading($layoutParagraphsForm.closest(".ui-dialog"));
-                $(btn)
-                  .trigger("mousedown")
-                  .trigger("click");
-              }
-            });
-            btn.style.display = "none";
-          });
-          const dialogConfig = {
-            width: "800px",
-            title: $layoutParagraphsForm
-              .find("[data-dialog-title]")
-              .attr("data-dialog-title"),
-            maxHeight: Math.max(400, $(window).height() * 0.8),
-            minHeight: Math.min($layoutParagraphsForm.outerHeight(), 400),
-            appendTo: $(".layout-paragraphs-form").parent(),
-            draggable: true,
-            autoResize: true,
-            modal: true,
-            buttons,
-            open() {
-              enhanceRadioSelect();
-            },
-            beforeClose(event) {
-              if (
-                isLoading($(event.target).closest(".layout-paragraphs-field"))
-              ) {
-                return false;
-              }
-              setLoading($(event.target).closest(".ui-dialog"));
-              $(event.target)
-                .find(".layout-paragraphs-cancel")
-                .trigger("mousedown")
-                .trigger("click");
-              return false;
-            }
-          };
-          $layoutParagraphsForm.dialog(dialogConfig);
+      $(".layout-paragraphs-item", context)
+        .once("layout-paragraphs-controls")
+        .each((layoutParagraphsItemIndex, layoutParagraphsItem) => {
+          $('<div class="layout-controls">')
+            .append($('<div class="layout-handle">'))
+            .append($('<div class="layout-up">').click(moveUp))
+            .append($('<div class="layout-down">').click(moveDown))
+            .prependTo(layoutParagraphsItem);
         });
-
       /**
        * Drag and drop with dragula.
        */
@@ -669,6 +632,14 @@
           updateFields($(item));
           updateDisabled($(item));
         });
+      /**
+       * Enhance radio buttons.
+       */
+      $(".layout-select--list", context)
+        .once("layout-select-enhance-radios")
+        .each((index, layoutList) => {
+          enhanceRadioSelect(layoutList);
+        });
     }
   };
 })(jQuery, Drupal, dragula);
diff --git a/src/Ajax/LayoutParagraphsInsertCommand.php b/src/Ajax/LayoutParagraphsInsertCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3bb6f52b6361181e58323e708507583eb8ad877
--- /dev/null
+++ b/src/Ajax/LayoutParagraphsInsertCommand.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\layout_paragraphs\Ajax;
+
+use Drupal\Core\Ajax\CommandInterface;
+use Drupal\Core\Ajax\CommandWithAttachedAssetsInterface;
+use Drupal\Core\Ajax\CommandWithAttachedAssetsTrait;
+
+/**
+ * Class LayoutParagraphsStateResetCommand.
+ */
+class LayoutParagraphsInsertCommand implements CommandInterface, CommandWithAttachedAssetsInterface {
+
+  use CommandWithAttachedAssetsTrait;
+
+  /**
+   * The layout element settings array.
+   *
+   * @var array
+   */
+  protected $settings;
+
+  /**
+   * The content for the matched element(s).
+   *
+   * Either a render array or an HTML string.
+   *
+   * @var string|array
+   */
+  protected $content;
+
+
+  /**
+   * Constructs a LayoutParagraphsInsertCommand instance.
+   */
+  public function __construct($settings, $content) {
+    $this->settings = $settings;
+    $this->content = $content;
+  }
+
+  /**
+   * Render custom ajax command.
+   *
+   * @return ajax
+   *   Command function.
+   */
+  public function render() {
+    return [
+      'command' => 'layoutParagraphsInsert',
+      'content' => $this->getRenderedContent(),
+      'settings' => $this->settings,
+    ];
+  }
+
+}
diff --git a/src/Ajax/LayoutParagraphsStateResetCommand.php b/src/Ajax/LayoutParagraphsStateResetCommand.php
index 1f2a5bc19dcfd655316ac34cc9c77fc61b914d9c..9da2edca84af9c3a3ce3e7731964665ee4561a37 100644
--- a/src/Ajax/LayoutParagraphsStateResetCommand.php
+++ b/src/Ajax/LayoutParagraphsStateResetCommand.php
@@ -31,7 +31,7 @@ class LayoutParagraphsStateResetCommand implements CommandInterface {
    */
   public function render() {
     return [
-      'command' => 'resetErlState',
+      'command' => 'resetLayoutParagraphsState',
       'data' => [
         "id" => $this->id,
       ],
diff --git a/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php b/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
index 6fccb2838c90a45250a58b9bc3d103419d4960d1..b8d81bb79121a4e0787dcf4853e2664302081b91 100644
--- a/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/LayoutParagraphsWidget.php
@@ -26,9 +26,15 @@ use Drupal\Core\Field\FieldFilteredMarkup;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
 use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Ajax\OpenDialogCommand;
+use Drupal\Core\Ajax\AppendCommand;
+use Drupal\Core\Ajax\PrependCommand;
+use Drupal\Core\Ajax\RemoveCommand;
+use Drupal\Core\Ajax\CloseDialogCommand;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\paragraphs\ParagraphInterface;
 use Drupal\layout_paragraphs\Ajax\LayoutParagraphsStateResetCommand;
+use Drupal\layout_paragraphs\Ajax\LayoutParagraphsInsertCommand;
 
 /**
  * Entity Reference with Layout field widget.
@@ -331,8 +337,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       '#limit_validation_errors' => [array_merge($parents, [$this->fieldName])],
       '#attributes' => ['class' => ['layout-paragraphs-add-item']],
       '#ajax' => [
-        'callback' => [$this, 'elementAjax'],
-        'wrapper' => $this->wrapperId,
+        'callback' => [$this, 'editItemAjax'],
       ],
       '#name' => implode('_', $parents) . '_add_item',
       '#element_parents' => $parents,
@@ -452,6 +457,10 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       return [];
     }
 
+    if (isset($widget_state_item['is_new'])) {
+      return;
+    }
+
     /** @var \Drupal\paragraphs\ParagraphInterface $entity */
     $entity = $widget_state_item['entity'];
     $layout_settings = $entity->getAllBehaviorSettings()['layout_paragraphs'] ?? [];
@@ -475,6 +484,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       $view_builder = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
       $preview = $view_builder->view($entity, $preview_view_mode);
       $preview['#cache']['max-age'] = 0;
+      $preview['#attributes']['class'][] = Html::cleanCssIdentifier($entity->uuid() . '-preview');
     }
 
     $element = [
@@ -489,6 +499,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       '#attributes' => [
         'class' => [
           'layout-paragraphs-item',
+          'paragraph-' . $entity->uuid(),
         ],
         'id' => [
           $this->fieldName . '--item-' . $delta,
@@ -511,7 +522,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
       'parent_uuid' => [
         '#type' => 'hidden',
         '#attributes' => ['class' => ['layout-paragraphs-parent-uuid']],
-        '#value' => $parent_uuid,
+        '#default_value' => $parent_uuid,
       ],
       'entity' => [
         '#type' => 'value',
@@ -532,8 +543,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
           '#submit' => [[$this, 'editItemSubmit']],
           '#delta' => $delta,
           '#ajax' => [
-            'callback' => [$this, 'elementAjax'],
-            'wrapper' => $this->wrapperId,
+            'callback' => [$this, 'editItemAjax'],
             'progress' => 'none',
           ],
           '#element_parents' => $parents,
@@ -547,8 +557,7 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
           '#submit' => [[$this, 'removeItemSubmit']],
           '#delta' => $delta,
           '#ajax' => [
-            'callback' => [$this, 'elementAjax'],
-            'wrapper' => $this->wrapperId,
+            'callback' => [$this, 'removeItemAjax'],
             'progress' => 'none',
           ],
           '#element_parents' => $parents,
@@ -576,7 +585,10 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
     // New items are rendered in layout but hidden.
     // This way we can track their weights, region names, etc.
     if (!empty($widget_state['items'][$delta]['is_new'])) {
-      $element['#attributes']['class'][] = 'js-hide';
+      $element['#is_new'] = TRUE;
+    }
+    else {
+      $element['#is_new'] = FALSE;
     }
 
     return $element;
@@ -596,10 +608,13 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
   public function buildLayouts(array $elements, FormStateInterface $form_state) {
     $tree = [];
     $paragraph_elements = [];
+    $elements['#items'] = [];
     foreach (Element::children($elements) as $index) {
       $element = $elements[$index];
       if (!empty($element['#widget_item'])) {
         $paragraph_elements[] = $element;
+        // Maintain a hidden flast list of elements to easily locate items.
+        $elements['#items'][$element['#entity']->uuid()] = $element;
         unset($elements[$index]);
       }
     }
@@ -879,20 +894,21 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
     $element['entity_form'] += [
       'actions' => [
         '#weight' => 1000,
-        '#type' => 'container',
+        '#type' => 'actions',
         '#attributes' => ['class' => ['layout-paragraphs-item-form-actions']],
         'save_item' => [
           '#type' => 'submit',
           '#name' => 'save',
           '#value' => $this->t('Save'),
           '#delta' => $delta,
+          '#uuid' => $entity->uuid(),
           '#limit_validation_errors' => [array_merge($parents, [$this->fieldName])],
           '#submit' => [
             [$this, 'saveItemSubmit'],
           ],
           '#ajax' => [
-            'callback' => [$this, 'elementAjax'],
-            'wrapper' => $this->wrapperId,
+            'callback' => [$this, 'saveItemAjax'],
+            //'wrapper' => $this->wrapperId,
             'progress' => 'none',
           ],
           '#element_parents' => $parents,
@@ -958,10 +974,10 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
           '#type' => 'submit',
           '#value' => $this->t('Remove'),
           '#delta' => $delta,
+          '#uuid' => $entity->uuid(),
           '#submit' => [[$this, 'removeItemConfirmSubmit']],
           '#ajax' => [
-            'callback' => [$this, 'elementAjax'],
-            'wrapper' => $this->wrapperId,
+            'callback' => [$this, 'removeItemConfirmAjax'],
             'progress' => 'none',
           ],
           '#element_parents' => $parents,
@@ -1158,12 +1174,22 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
   public function removeItemConfirmSubmit($form, $form_state) {
 
     $element = $form_state->getTriggeringElement();
+    $uuid = $element['#uuid'];
     $parents = $element['#element_parents'];
     $delta = $element['#delta'];
 
     $widget_state = static::getWidgetState($parents, $this->fieldName, $form_state);
 
     unset($widget_state['items'][$delta]);
+    foreach ($widget_state['items'] as $delta => $item) {
+      /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+      $paragraph = $item['entity'];
+      $behavior_settings = $paragraph->getAllBehaviorSettings()['layout_paragraphs'];
+      if (isset($behavior_settings['parent_uuid']) && $behavior_settings['parent_uuid'] == $uuid) {
+        unset($widget_state['items'][$delta]);
+      }
+
+    }
     $widget_state['remove_item'] = FALSE;
 
     static::setWidgetState($parents, $this->fieldName, $form_state, $widget_state);
@@ -1277,13 +1303,150 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
     $parents = $element['#element_parents'];
     $field_state = static::getWidgetState($parents, $this->fieldName, $form_state);
     $widget_field = NestedArray::getValue($form, $field_state['array_parents']);
+    $html_id = $this->entityFormHtmlId($field_state);
 
     $response = new AjaxResponse();
+    $response->addCommand(new CloseDialogCommand('#' . $html_id));
     $response->addCommand(new ReplaceCommand('#' . $this->wrapperId, $widget_field));
     $response->addCommand(new LayoutParagraphsStateResetCommand('#' . $this->wrapperId));
     return $response;
   }
 
+  /**
+   * Ajax callback to return the entire ERL element.
+   */
+  public function saveItemAjax(array $form, FormStateInterface $form_state) {
+    $triggering_element = $form_state->getTriggeringElement();
+    $uuid = $triggering_element['#uuid'];
+    $parents = $triggering_element['#element_parents'];
+    $field_state = static::getWidgetState($parents, $this->fieldName, $form_state);
+    $widget_field = NestedArray::getValue($form, $field_state['array_parents']);
+    $html_id = $this->entityFormHtmlId($field_state);
+
+    $element = static::findElementByUuid($widget_field['active_items']['items'], $uuid);
+    /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
+    $paragraph = $element['#entity'];
+    $behavior_settings = $paragraph->getAllBehaviorSettings()['layout_paragraphs'];
+
+    if ($behavior_settings['parent_uuid'] && $behavior_settings['region']) {
+      $parent_selector = '.paragraph-' . $behavior_settings['parent_uuid'] . ' .layout-paragraphs-layout-region--' . $behavior_settings['region'];
+    }
+    else {
+      $parent_selector = '';
+    }
+
+    $settings = [
+      'wrapper_selector' => '#' . $this->wrapperId,
+      'selector' => '.paragraph-' . $uuid,
+      'parent_selector' => $parent_selector,
+      'weight' => $element['#weight'],
+    ];
+
+    $response = new AjaxResponse();
+    $response->addCommand(new LayoutParagraphsInsertCommand($settings, $element));
+    $response->addCommand(new CloseDialogCommand('#' . $html_id));
+    return $response;
+  }
+
+  /**
+   * Recursively search the build array for element with matching uuid.
+   *
+   * @param array $array
+   *   Nested build array.
+   * @param string $uuid
+   *   The uuid of the element to find.
+   *
+   * @return array
+   *   The matching element build array.
+   */
+  public static function findElementByUuid(array $array, string $uuid) {
+    $element = FALSE;
+    foreach ($array as $key => $item) {
+      if (is_array($item)) {
+        if (isset($item['#entity'])) {
+          if ($item['#entity']->uuid() == $uuid) {
+            return $item;
+          }
+        }
+        if (isset($item['preview']['regions'])) {
+          foreach (Element::children($item['preview']['regions']) as $region_name) {
+            if ($element = static::findElementByUuid($item['preview']['regions'][$region_name], $uuid)) {
+              return $element;
+            }
+          }
+        }
+      }
+    }
+    return $element;
+  }
+
+  /**
+   * Ajax callback to return the entire ERL element.
+   */
+  public function editItemAjax(array $form, FormStateInterface $form_state) {
+    $element = $form_state->getTriggeringElement();
+    $parents = $element['#element_parents'];
+    $field_state = static::getWidgetState($parents, $this->fieldName, $form_state);
+    $widget_field = NestedArray::getValue($form, $field_state['array_parents']);
+    $entity_form = $widget_field['entity_form'];
+    $html_id = $this->entityFormHtmlId($field_state);
+
+    $dialog_options = [
+      'modal' => TRUE,
+      'appendTo' => '#' . $this->wrapperId,
+      'width' => 800,
+      'drupalAutoButtons' => TRUE,
+    ];
+
+    $response = new AjaxResponse();
+    $response->addCommand(new AppendCommand('#' . $this->wrapperId, '<div id="' . $html_id . '"></div>'));
+    $response->addCommand(new OpenDialogCommand('#' . $html_id, 'Edit Form', $entity_form, $dialog_options));
+    $response->addCommand(new LayoutParagraphsStateResetCommand('#' . $this->wrapperId));
+    return $response;
+  }
+
+  /**
+   * Ajax callback to remove an item - launches confirmation dialog.
+   */
+  public function removeItemAjax(array $form, FormStateInterface $form_state) {
+    $element = $form_state->getTriggeringElement();
+    $parents = $element['#element_parents'];
+    $field_state = static::getWidgetState($parents, $this->fieldName, $form_state);
+    $widget_field = NestedArray::getValue($form, $field_state['array_parents']);
+    $entity_form = $widget_field['remove_form'];
+    $html_id = $this->entityFormHtmlId($field_state);
+
+    $dialog_options = [
+      'modal' => TRUE,
+      'appendTo' => '#' . $this->wrapperId,
+      'width' => 800,
+      'drupalAutoButtons' => TRUE,
+    ];
+
+    $response = new AjaxResponse();
+    $response->addCommand(new AppendCommand('#' . $this->wrapperId, '<div id="' . $html_id . '"></div>'));
+    $response->addCommand(new OpenDialogCommand('#' . $html_id, 'Edit Form', $entity_form, $dialog_options));
+    $response->addCommand(new LayoutParagraphsStateResetCommand('#' . $this->wrapperId));
+    return $response;
+  }
+
+
+  /**
+   * Ajax callback to remove an item - removes item from DOM.
+   */
+  public function removeItemConfirmAjax(array $form, FormStateInterface $form_state) {
+    $element = $form_state->getTriggeringElement();
+    $uuid = $element['#uuid'];
+    $parents = $element['#element_parents'];
+    $field_state = static::getWidgetState($parents, $this->fieldName, $form_state);
+    $html_id = $this->entityFormHtmlId($field_state);
+
+    $response = new AjaxResponse();
+    $response->addCommand(new RemoveCommand('.paragraph-' . $uuid));
+    $response->addCommand(new CloseDialogCommand('#' . $html_id));
+    return $response;
+  }
+
   /**
    * Ajax callback to return a layout plugin configuration form.
    */
@@ -1304,6 +1467,19 @@ class LayoutParagraphsWidget extends WidgetBase implements ContainerFactoryPlugi
     }
   }
 
+  /**
+   * Generates an ID for the entity form dialog container.
+   *
+   * @param array $field_state
+   *   The field state with array_parents.
+   *
+   * @return string
+   *   The HTML id.
+   */
+  private function entityFormHtmlId(array $field_state) {
+    return trim(Html::getId(implode('-', $field_state['array_parents']) . '-entity-form'), '-');
+  }
+
   /**
    * Field instance settings form.
    */