diff --git a/css/paragraphs.admin.css b/css/paragraphs.admin.css
index 58971cc..cb23792 100644
--- a/css/paragraphs.admin.css
+++ b/css/paragraphs.admin.css
@@ -80,3 +80,39 @@
   padding-right: 10px;
   text-align: right;
 }
+
+
+.js .paragraph-type-add-modal {
+  width: 100%;
+  padding: 10px 0;
+  text-align: center;
+  margin-bottom: -3rem;
+  height: 30px;
+}
+
+.js .paragraph-type-add-modal.first-button {
+  margin-top: -32px;
+  margin-bottom:-20px;
+}
+
+.js .clearfix > .paragraph-type-add-modal.first-button {
+  margin-left: 12px;
+  margin-top: -2em;
+  margin-bottom: -1em;
+}
+
+
+.js .paragraph-type-add-modal.no-paragraphs {
+  margin-bottom: -1em;
+  margin-top: 2em;
+}
+
+.js .paragraph-type-add-modal-button {
+  display: inline-block;
+  margin: 0 auto;
+}
+
+.js .paragraph-type-add-modal-button:hover {
+  color: #ffffff;
+  background: #057ec7 none;
+}
diff --git a/css/paragraphs.list-builder.scss b/css/paragraphs.list-builder.scss
deleted file mode 100644
index 609b836..0000000
--- a/css/paragraphs.list-builder.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-
-.paragraphs-type-icon {
-  width: 50px;
-  img {
-    display: block;
-  }
-}
diff --git a/css/paragraphs.modal.css b/css/paragraphs.modal.css
new file mode 100644
index 0000000..01aa393
--- /dev/null
+++ b/css/paragraphs.modal.css
@@ -0,0 +1,12 @@
+ul.paragraphs-add-dialog-list {
+  margin: 0;
+  list-style-type: none;
+}
+
+.paragraphs-add-dialog-row {
+  padding: 5px;
+}
+
+.paragraphs-add-dialog-row button {
+  width: 200px;
+}
diff --git a/css/paragraphs.widget.css b/css/paragraphs.widget.css
index 8418e32..534c88e 100644
--- a/css/paragraphs.widget.css
+++ b/css/paragraphs.widget.css
@@ -2,6 +2,7 @@
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
   display: inline-flex;
+  text-align: right;
 }
 
 .js .field--widget-paragraphs .dropbutton-wrapper {
@@ -19,7 +20,7 @@
 }
 
 .js .field--widget-paragraphs td {
-  padding: 10px 0;
+  padding: 0;
 }
 
 .js .field--widget-paragraphs .field-multiple-drag {
@@ -41,6 +42,10 @@
   text-align: right;
 }
 
+.js-form-wrapper .form-wrapper {
+  padding-bottom: .5rem;
+}
+
 .js .paragraph-type-top {
   display: -webkit-flex;
   display: -ms-flexbox;
@@ -92,6 +97,77 @@
   overflow: hidden;
 }
 
+.js .paragraph-type-add-modal {
+  width: 100%;
+  padding: 10px 0;
+  text-align: center;
+  height: 30px;
+  margin-top: -2em;
+  margin-bottom: -3em;
+}
+
+.js .paragraph-type-add-modal.first-button{
+  margin-top: -40px;
+  margin-bottom: 15px;
+}
+
+.js .clearfix > .paragraph-type-add-modal.first-button {
+  margin-left: 12px;
+}
+
+.js .paragraph-type-add-modal.no-paragraphs {
+  margin-bottom: -1em;
+  margin-top: 2em;
+}
+
+.js .paragraph-type-add-modal-button {
+  display: none;
+  margin: 0 auto;
+  margin-top: 1em;
+  border-radius: 0px;
+  width: 100%;
+  height: 100%;
+  border: none;
+  background-color: #2369a6;
+  background-image: none;
+  color: #ffffff;
+  text-transform: uppercase;
+  font-weight: 700;
+  -webkit-animation-name: button-animate-on;
+  -webkit-animation-duration: 0.4s;
+  animation-name: button-animate-on;
+  animation-duration: 0.4s;
+}
+
+.paragraph-button-open {
+  display: inline-block!important;
+}
+
+.first-paragraph-add-button {
+  display: inline-block!important;
+}
+
+/* Add Animation */
+@-webkit-keyframes button-animate-on {
+  from {height:0%; opacity:0}
+  to {height:100%; opacity:1}
+}
+
+@keyframes button-animate-on {
+  from {height:0%; opacity:0}
+  to {height:100%; opacity:1}
+}
+
+.js .paragraph-type-add-modal-button:hover {
+  color: #ffffff;
+  background: #2369a6;
+  background-image: linear-gradient(to bottom, #0c97ed, #1f86c7);
+}
+
+.js .first-button {
+  padding-top: 1em;
+}
+
 .paragraph--view-mode--preview {
   padding-right: 1em;
 }
diff --git a/css/paragraphs.widget.scss b/css/paragraphs.widget.scss
deleted file mode 100644
index 6c7ca38..0000000
--- a/css/paragraphs.widget.scss
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-// @file
-// Experimental paragraphs widget CSS.
-//
-
-// We are using .js prefix here mainly because we want to apply this style rules
-// only for JS version of a widget.
-.js {
-  .field--widget-paragraphs {
-    .paragraphs-dropbutton-wrapper {
-      // We are using inline-flex here so 'Add type' dropdown button is inline
-      // and aligned 'to type' text.
-      display: inline-flex;
-    }
-
-    .dropbutton-wrapper {
-      // Override 600px breakpoint from core, needed again so 'to type' is in
-      // the same line with add dropdown button.
-      width: auto;
-
-      // Reset some CSS that are coming from core.
-      margin-right: 0;
-      padding-right: 0;
-    }
-
-    // Reset some CSS that are coming from core.
-    .dropbutton-widget {
-      position: static;
-    }
-
-    .field-multiple-table {
-      margin-bottom: 10px;
-    }
-
-    td { // stylelint-disable-line selector-no-type
-      padding: 10px 0;
-    }
-
-    .field-multiple-drag {
-      vertical-align: top;
-    }
-
-    .draggable .tabledrag-handle {
-      margin-left: 0;
-    }
-
-    .tabledrag-handle .handle {
-      margin-right: 0;
-      margin-left: 0;
-      padding-right: 0.2em;
-    }
-
-    .delta-order {
-      padding-right: 10px;
-      text-align: right;
-    }
-  }
-
-  .paragraph-type-top {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-  }
-
-  .paragraphs-collapsed-description {
-    position: relative;
-    width: 100%;
-    height: 1.538em;
-    padding-right: 1em;
-    padding-left: 1em;
-    color: #777;
-    overflow: hidden;
-    word-break: break-all;
-
-    &::after {
-      display: block;
-      position: absolute;
-      top: 0;
-      right: 1em;
-      width: 3em;
-      background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, #fff 100%);
-      content: "\00a0";
-    }
-  }
-
-  .draggable:hover .paragraphs-collapsed-description {
-    &::after {
-      background: linear-gradient(to right, rgba(247, 252, 255, 0) 0%, #f7fcff 100%);
-    }
-  }
-
-  .drag-previous .paragraphs-collapsed-description {
-    &::after {
-      background: linear-gradient(to right, rgba(255, 255, 221, 0) 0%, #ffd 100%);
-    }
-  }
-
-  .paragraph-type-title {
-    flex-basis: 25%;
-    min-width: 80px;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    overflow: hidden;
-  }
-}
-
-.paragraph--view-mode--preview {
-  padding-right: 1em;
-}
-
-.paragraphs-edit-button-container {
-  display: flex;
-  flex-flow: row-reverse;
-  margin-left: auto;
-  padding-right: 1em;
-  padding-left: 1em;
-
-  // Override 600px breakpoint core submit button tweaks.
-  @media screen and (max-width: 600px) {
-    .js & {
-      width: 50px;
-      height: 40px;
-    }
-  }
-
-}
-
-.paragraphs-tabs-wrapper {
-  .paragraphs-tabs {
-    display: none;
-  }
-}
-
-.is-horizontal .paragraphs-tabs .tabs__tab {
-  border-bottom: 0;
-}
diff --git a/js/paragraphs.modal.js b/js/paragraphs.modal.js
new file mode 100644
index 0000000..c512973
--- /dev/null
+++ b/js/paragraphs.modal.js
@@ -0,0 +1,286 @@
+/**
+ * @file paragraphs.modal.js
+ *
+ */
+
+(function ($, Drupal, drupalSettings) {
+
+  'use strict';
+
+  /**
+   * Handling of hover state for add buttons.
+   *
+   * @type {Object}
+   */
+  Drupal.behaviors.modalHover = {
+    attach: function (context) {
+      var $buttonName = '.paragraph-type-add-modal-button';
+      var $buttonClass = 'paragraph-button-open';
+
+      $("input[id*='-add-more-first-button-area-add-more']").addClass('first-paragraph-add-button');
+
+      // Find all matching id's and add class on hover over unique id's.
+      $('.paragraph-type-add-modal', context).hover(
+          function() {
+            $(this)
+                .children($buttonName)
+                .addClass($buttonClass);
+          },
+          function() {
+            $(this)
+                .find($buttonName)
+                .removeClass($buttonClass);
+          }
+      );
+    }
+  }
+
+  /**
+   * Method to apply data on template element.
+   *
+   * For more information about template please take a look at documentation
+   * provided in: templates/paragraphs-add-dialog.html.twig
+   *
+   * @param {Object} $templateElement
+   *   jQuery element for template element.
+   * @param {Object} data
+   *   Data object used to apply on template.
+   *
+   * @private
+   */
+  var _templateApplyData = function ($templateElement, data) {
+    $.each(data, function (name, value) {
+      var selector = '[data-' + name + ']';
+
+      $templateElement.find(selector)
+        .addBack(selector)
+        .each(function (index, childElement) {
+          var $child = $(childElement);
+          var attrName = $child.attr('data-' + name);
+          $child.removeAttr('data-' + name);
+
+          if (attrName === 'content') {
+            $child.text(value);
+          }
+          else {
+            $child.attr(attrName, value);
+          }
+        });
+    });
+  };
+
+  /**
+   * Method to clone template and apply data on it.
+   *
+   * @param {Object} $template
+   *   jQuery element for template element used for cloning.
+   * @param {Object} data
+   *   Data object used to apply on template.
+   *
+   * @return {Object}
+   *   Returns cloned template with applied data on it.
+   *
+   * @private
+   */
+  var _templateClone = function ($template, data) {
+    var $templateClone = $template
+      .clone()
+      .appendTo($template.parent());
+
+    // Adjust all CSS classes with suffix "-template".
+    var classEnding = '-template';
+    $.each(
+      $templateClone.attr('class').toString().split(' '),
+      function (index, className) {
+        if (className.substr(-classEnding.length) === classEnding) {
+          var newClassName = className.substr(0, className.length - classEnding.length);
+          $templateClone
+            .removeClass(className)
+            .toggleClass(newClassName);
+        }
+      }
+    );
+
+    _templateApplyData($templateClone, data);
+
+    return $templateClone;
+  };
+
+  /**
+   * Click handler for click "+ Add" button between paragraphs.
+   *
+   * @type {Object}
+   */
+  Drupal.behaviors.modalAdd = {
+    attach: function (context) {
+      $('.paragraph-type-add-modal-button', context)
+        .once('add-click-handler')
+        .on('click', function (event) {
+          var $button = $(this);
+
+          // Stop default execution of click event.
+          event.preventDefault();
+          event.stopPropagation();
+
+          // Global data for dialog template.
+          // delta: '' -> means that paragraph will be added to end of list.
+          var config = {delta: ''};
+
+          // Get wrapper of elements used for submitting of add paragraph
+          // functionality. It's also used as context for opening of dialog.
+          var $addMoreWrapper;
+          if ($button.attr('name') === 'first_button_add_modal') {
+            // Case for last button in list (of for empty list).
+            $addMoreWrapper = $button
+              .parent()
+              .siblings('.js-hide')
+              .parent();
+          }
+          else {
+            // For button between paragraphs.
+            $addMoreWrapper = $button
+              .closest('table')
+              .parent()
+              .find('.paragraphs-add-dialog-template')
+              .parent();
+
+            // Set delta to correct position in list of paragraphs.
+            config.delta = $button.closest('tr').index();
+          }
+
+          // Get types from ComboBox.
+          var paragraphTypes = Drupal.modalAddParagraphs.getParagraphTypes($addMoreWrapper.find('[name$="[add_more_select]"]'));
+
+          // Open dialog in context of "add_more" element, with provided
+          // configuration and list of paragraph types.
+          Drupal.modalAddParagraphs.openDialog($addMoreWrapper, config, paragraphTypes);
+        });
+    }
+  };
+
+  /**
+   * Namespace for modal related javascript methods.
+   *
+   * @type {Object}
+   */
+  Drupal.modalAddParagraphs = {};
+
+  /**
+   * Fetch list of paragraph types from options provided in combobox.
+   *
+   * @param {Object} $typeComboBox
+   *   jQuery element of combobox with list of available paragraph types.
+   *
+   * @return {Array}
+   *   List of paragraph type objects with type and it's name.
+   */
+  Drupal.modalAddParagraphs.getParagraphTypes = function ($typeComboBox) {
+    var paragraphTypes = [];
+
+    $typeComboBox.find('option').each(function (index, optionElement) {
+      var $option = $(optionElement);
+
+      paragraphTypes.push(
+        {
+          'type': $option.attr('value'),
+          'type-name': $option.text(),
+        }
+      );
+    });
+
+    return paragraphTypes;
+  };
+
+  /**
+   * Open modal dialog for adding new paragraph in list.
+   *
+   * @param {Object} $context
+   *   jQuery element of form wrapper used to submit request for adding new
+   *   paragraph to list. Wrapper also contains dialog template.
+   * @param {Object} config
+   *   Global configuration for dialog template. It will be applied on dialog
+   *   template to generated customized dialog.
+   * @param {Array} paragraphTypes
+   *   List of objects with information for paragraph type. Every object
+   *   contains type and name for it and list is used to generate correct action
+   *   elements in customized dialog.
+   */
+  Drupal.modalAddParagraphs.openDialog = function ($context, config, paragraphTypes) {
+
+    // Get dialog template and apply data on it.
+    var $dialogTemplate = $('.paragraphs-add-dialog-template', $context);
+    var $dialog = _templateClone($dialogTemplate, config);
+
+    // Get row template and duplicate it for every paragraph type.
+    var $rowTemplate = $dialog.find('.paragraphs-add-dialog-row-template');
+    for (var i = 0; i < paragraphTypes.length; i++) {
+      _templateClone($rowTemplate, paragraphTypes[i]);
+    }
+    $rowTemplate.remove();
+
+    // Open dialog after data is applied on template.
+    $dialog.dialog({
+      modal: true,
+      resizable: false,
+      close: function () {
+        var $dialog = $(this);
+
+        // Destroy dialog object.
+        $dialog.dialog('destroy');
+
+        // Remove created html element for dialog.
+        $dialog.remove();
+      }
+    });
+
+    // Attach behaviours to dialog action triggering elements.
+    $('.paragraphs-add-type-trigger-element', $dialog)
+      .once('add-click-handler')
+      .on('click', function (event) {
+        var $this = $(this);
+
+        // Stop default execution of click event.
+        event.preventDefault();
+        event.stopPropagation();
+
+        Drupal.modalAddParagraphs.setValues(
+          $context,
+          {
+            add_more_select: $this.attr('data-type'),
+            add_more_delta: $this.attr('data-delta'),
+          }
+        );
+
+        // Close dialog afterwards.
+        $this.closest('div.ui-dialog-content').dialog('close');
+      });
+  };
+
+  /**
+   * Method to set hidden fields and trigger adding of paragraph.
+   *
+   * @param {Object} $context
+   *   Jquery object containing element where form for submitting exists.
+   * @param {Object} options
+   *   Object with key value pair, where key is name of field that should be set
+   *   and value is value for that field.
+   */
+  Drupal.modalAddParagraphs.setValues = function ($context, options) {
+    var $submitButton = $('.js-hide input[name$="_add_more"]', $context);
+    var $wrapper = $submitButton.parent();
+
+    // Set all field values defined in options.
+    $.each(options, function (fieldName, fieldValue) {
+      var $field = $wrapper.find('[name$="[' + fieldName + ']"]');
+
+      if ($field) {
+        $field.val(fieldValue);
+      }
+    });
+
+    // Trigger ajax call on add button.
+    $submitButton.trigger('mousedown');
+
+  };
+
+}(jQuery, Drupal, drupalSettings));
diff --git a/paragraphs.libraries.yml b/paragraphs.libraries.yml
index 4186157..3e197b2 100644
--- a/paragraphs.libraries.yml
+++ b/paragraphs.libraries.yml
@@ -31,3 +31,15 @@ drupal.paragraphs.list_builder:
   css:
     theme:
       css/paragraphs.list-builder.css: {}
+
+drupal.paragraphs.modal:
+  js:
+    js/paragraphs.modal.js: {}
+  css:
+    theme:
+      css/paragraphs.modal.css: {}
+  dependencies:
+    - core/drupal.dialog.ajax
+    - core/jquery.once
+    - core/jquery.ui.tabs
+    - core/drupal
diff --git a/paragraphs.module b/paragraphs.module
index ea43d9e..17faaa9 100644
--- a/paragraphs.module
+++ b/paragraphs.module
@@ -57,6 +57,11 @@ function paragraphs_theme() {
     'paragraphs_dropbutton_wrapper' => array(
       'variables' => array('children' => NULL),
     ),
+    'paragraphs_add_dialog' => [
+      'variables' => [],
+      'template' => 'paragraphs-add-dialog',
+//      'render element' => 'elements',
+    ],
   );
 }
 
diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
index 43aa267..55801f9 100644
--- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -137,7 +137,8 @@ class InlineParagraphsWidget extends WidgetBase {
       '#options' => array(
         'select' => $this->t('Select list'),
         'button' => $this->t('Buttons'),
-        'dropdown' => $this->t('Dropdown button')
+        'dropdown' => $this->t('Dropdown button'),
+        'modal' => $this->t('Modal form'),
       ),
       '#default_value' => $this->getSetting('add_mode'),
       '#required' => TRUE,
@@ -203,6 +204,9 @@ class InlineParagraphsWidget extends WidgetBase {
       case 'dropdown':
         $add_mode = $this->t('Dropdown button');
         break;
+      case 'modal':
+        $add_mode = $this->t('Modal form');
+        break;
     }
 
     $summary[] = $this->t('Edit mode: @edit_mode', ['@edit_mode' => $edit_mode]);
@@ -262,17 +266,6 @@ class InlineParagraphsWidget extends WidgetBase {
         }
       }
     }
-    elseif (isset($widget_state['selected_bundle'])) {
-
-      $entity_type = $entity_manager->getDefinition($target_type);
-      $bundle_key = $entity_type->getKey('bundle');
-
-      $paragraphs_entity = $entity_manager->getStorage($target_type)->create(array(
-        $bundle_key => $widget_state['selected_bundle'],
-      ));
-
-      $item_mode = 'edit';
-    }
 
     if ($item_mode == 'collapsed') {
       $item_mode = $default_edit_mode;
@@ -692,6 +685,10 @@ class InlineParagraphsWidget extends WidgetBase {
       $widget_state['paragraphs'][$delta]['display'] = $display;
       $widget_state['paragraphs'][$delta]['mode'] = $item_mode;
 
+      if ($this->getSetting('add_mode') == 'modal') {
+        $this->buildInBetweenAddButton($element, $id_prefix);
+      }
+
       static::setWidgetState($parents, $field_name, $form_state, $widget_state);
     }
     else {
@@ -702,6 +699,54 @@ class InlineParagraphsWidget extends WidgetBase {
   }
 
   /**
+   * Builds an add paragraph button between paragraphs for opening of modal.
+   *
+   * @param array $element
+   *   Render element.
+   * @param string $id_prefix
+   *   Prefix.
+   */
+  protected function buildInBetweenAddButton(array &$element, $id_prefix) {
+    if (empty($this->uuid)) {
+      $this->uuid = \Drupal::service('uuid')->generate();
+    }
+
+    $element[$id_prefix . '_area'] = [
+      '#type' => 'container',
+      '#attributes' => [
+        'class' => [
+          'paragraph-type-add-modal',
+          'first-button',
+        ],
+      ],
+      '#access' => !$this->isTranslating,
+      '#weight' => -2000,
+    ];
+
+    $paragraph_types = paragraphs\Entity\ParagraphType::loadMultiple();
+
+    $element[$id_prefix . '_area']['add_more'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('+ Add'),
+      '#name' => strtr($id_prefix, '-', '_') . '_add_modal',
+      '#attributes' => [
+        'class' => [
+          'paragraph-type-add-modal-button',
+          'button--small',
+          'js-show',
+        ]
+      ],
+    ];
+    foreach($paragraph_types as $paragraph_type) {
+      if ($paragraph_type->getIconUrl()) {
+        $element[$id_prefix . '_area']['add_more']['#attributes']['data-' . $paragraph_type->get('id')] = $paragraph_type->getIconUrl();
+      }
+    }
+
+    $element['#attached']['library'][] = 'paragraphs/drupal.paragraphs.modal';
+  }
+
+  /**
    * Returns the sorted allowed types for a entity reference field.
    *
    * @return array
@@ -836,6 +881,7 @@ class InlineParagraphsWidget extends WidgetBase {
 
     $field_state = static::getWidgetState($this->fieldParents, $field_name, $form_state);
     $field_state['real_item_count'] = $this->realItemCount;
+    $field_state['add_mode'] = $this->getSetting('add_mode');
     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
 
     $elements += [
@@ -940,7 +986,7 @@ class InlineParagraphsWidget extends WidgetBase {
         ];
       }
 
-      return $add_more_elements ;
+      return $add_more_elements;
     }
 
     if ($this->getSetting('add_mode') == 'button' || $this->getSetting('add_mode') == 'dropdown') {
@@ -1043,7 +1089,24 @@ class InlineParagraphsWidget extends WidgetBase {
   protected function buildSelectAddMode() {
     $field_name = $this->fieldDefinition->getName();
     $title = $this->fieldDefinition->getLabel();
-    $add_more_elements['add_more_select'] = [
+
+    $add_more_elements = [];
+
+    // Add button at end of list, when modal dialog is used to add paragraphs.
+    if ($this->getSetting('add_mode') == 'modal') {
+      $this->buildInBetweenAddButton($add_more_elements, 'first-button');
+
+      // Append template for modal add paragraph dialog.
+      $add_more_elements['paragraphs_add_dialog_template'] = $this->getModalAddDialogTemplate();
+
+      // Selection form elements.
+      $selection_form_elements['add_more_delta'] = [
+        '#type' => 'hidden',
+        '#title' => 'Delta',
+      ];
+    }
+
+    $selection_form_elements['add_more_select'] = [
       '#type' => 'select',
       '#options' => $this->getAccessibleOptions(),
       '#title' => $this->t('@title type', ['@title' => $this->getSetting('title')]),
@@ -1051,12 +1114,11 @@ class InlineParagraphsWidget extends WidgetBase {
     ];
 
     $text = $this->t('Add @title', ['@title' => $this->getSetting('title')]);
-
     if ($this->realItemCount > 0) {
       $text = $this->t('Add another @title', ['@title' => $this->getSetting('title')]);
     }
 
-    $add_more_elements['add_more_button'] = [
+    $selection_form_elements['add_more_button'] = [
       '#type' => 'submit',
       '#name' => strtr($this->fieldIdPrefix, '-', '_') . '_add_more',
       '#value' => $text,
@@ -1069,8 +1131,18 @@ class InlineParagraphsWidget extends WidgetBase {
         'effect' => 'fade',
       ],
     ];
+    $selection_form_elements['add_more_button']['#suffix'] = $this->t(' to %type', ['%type' => $title]);
+
+    // If we have a modal, the selection form should be hidden.
+    if ($this->getSetting('add_mode') == 'modal') {
+      $add_more_elements['selection_form'] = $selection_form_elements;
+      $add_more_elements['selection_form']['#type'] = 'container';
+      $add_more_elements['selection_form']['#attributes']['class'][] = 'js-hide';
+    }
+    else {
+      $add_more_elements = $selection_form_elements;
+    }
 
-    $add_more_elements['add_more_button']['#suffix'] = $this->t(' to %type', ['%type' => $title]);
     return $add_more_elements;
   }
 
@@ -1096,6 +1168,10 @@ class InlineParagraphsWidget extends WidgetBase {
     $button = $form_state->getTriggeringElement();
     // Go one level up in the form, to the widgets container.
     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
+    // The structure of modal is different.
+    if (!isset($element['#field_name'])) {
+      $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3));
+    }
 
     // Add a DIV around the delta receiving the Ajax effect.
     $delta = $element['#max_delta'];
@@ -1113,6 +1189,11 @@ class InlineParagraphsWidget extends WidgetBase {
 
     // Go one level up in the form, to the widgets container.
     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
+    // The structure of modal is different.
+    if (!isset($element['#field_name'])) {
+      $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3));
+    }
+
     $field_name = $element['#field_name'];
     $parents = $element['#field_parents'];
 
@@ -1121,20 +1202,104 @@ class InlineParagraphsWidget extends WidgetBase {
 
     if ($widget_state['real_item_count'] < $element['#cardinality'] || $element['#cardinality'] == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
       $widget_state['items_count']++;
+      $widget_state['real_item_count']++;
     }
 
+    $position = $widget_state['real_item_count'] - 1;
     if (isset($button['#bundle_machine_name'])) {
       $widget_state['selected_bundle'] = $button['#bundle_machine_name'];
     }
+    elseif ($widget_state['add_mode'] == 'modal') {
+      $widget_state['selected_bundle'] = $element['add_more']['selection_form']['add_more_select']['#value'];
+      if ($element['add_more']['selection_form']['add_more_delta']['#value'] !== "") {
+        $position = $element['add_more']['selection_form']['add_more_delta']['#value'];
+      }
+    }
     else {
       $widget_state['selected_bundle'] = $element['add_more']['add_more_select']['#value'];
     }
 
+    // Create new paragraph entity.
+    $entity_type = \Drupal::entityTypeManager()->getDefinition('paragraph');
+    $bundle_key = $entity_type->getKey('bundle');
+
+    $paragraphs_entity = \Drupal::entityTypeManager()->getStorage('paragraph')->create(array(
+      $bundle_key => $widget_state['selected_bundle'],
+    ));
+
+    $paragraph = [
+      'entity' => $paragraphs_entity,
+      'mode' => 'edit',
+    ];
+
+    if (isset($widget_state['paragraphs'][$position])) {
+      $paragraph['display'] = $widget_state['paragraphs'][$position]['display'];
+    }
+
+    // Add paragraph to the widget state.
+    // This also creates it, when it doesn't exist.
+    $widget_state['paragraphs'][] = $paragraph;
+
+    // If we use a modal, we have to place the new paragraph
+    // in the correct position.
+    if ($widget_state['add_mode'] == 'modal') {
+      // Clean form_state.
+      $user_input = $user_input_save = $form_state->getUserInput();
+
+      // Temporarily remove 'add_more' from array.
+      unset($user_input[$field_name]['add_more']);
+
+      self::normalizeWeights($user_input[$field_name], $position);
+
+      // It is important, that the key maps with the one from $widget_state
+      // The weight handles the position.
+      $key = count($widget_state['paragraphs']) - 1;
+      $item[$key] = [
+        'subform' => [],
+        '_weight' => $position,
+      ];
+
+      $user_input[$field_name] += $item;
+
+      // Add back 'add_more'.
+      $user_input[$field_name]['add_more'] = $user_input_save[$field_name];
+
+      $form_state->setUserInput($user_input);
+    }
+
     static::setWidgetState($parents, $field_name, $form_state, $widget_state);
 
     $form_state->setRebuild();
   }
 
+  /**
+   * This resets the weights, ascending, starting from 0.
+   *
+   * It keeps the indices.
+   *
+   * E.g. [-6, -5, -4] will become [0, 1, 2]
+   *
+   * Starting at position, the elements will get weight+1, to make space
+   * for a new element.
+   *
+   * E.g. [-6, -5, -4], position = 1, will become [ 0,  2,  3]
+   *
+   * @param array $array
+   *   The array, which weights should be normalised.
+   * @param int $position
+   *   The position from which on the weights will be increased by 1.
+   */
+  private static function normalizeWeights(array &$array, $position) {
+    $weigth = 0;
+    foreach ($array as &$value) {
+      if ($weigth == $position) {
+        $weigth++;
+      }
+      $value['_weight'] = $weigth;
+      $weigth++;
+    }
+  }
+
   public static function paragraphsItemSubmit(array $form, FormStateInterface $form_state) {
     $button = $form_state->getTriggeringElement();
 
@@ -1428,7 +1593,8 @@ class InlineParagraphsWidget extends WidgetBase {
    * @return int
    *   The number of paragraphs is the given mode.
    */
-  protected function getNumberOfParagraphsInMode(array $widget_state, $mode) {
+  protected function getNumberOfParagraphsInMode(array $widget_state, $mode)
+  {
     if (!isset($widget_state['paragraphs'])) {
       return 0;
     }
@@ -1444,6 +1610,21 @@ class InlineParagraphsWidget extends WidgetBase {
   }
 
   /**
+   * Returns render array for template of add paragraph modal dialog.
+   *
+   * @return array
+   *   Render array.
+   */
+  protected function getModalAddDialogTemplate() {
+    return [
+      '#theme' => 'paragraphs_add_dialog',
+      '#attached' => [
+        'library' => ['paragraphs/drupal.paragraphs.modal'],
+      ],
+    ];
+  }
+
+  /**
    * {@inheritdoc}
    */
   public static function isApplicable(FieldDefinitionInterface $field_definition) {
diff --git a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
index a82ee34..1814a2e 100644
--- a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
@@ -131,7 +131,8 @@ class ParagraphsWidget extends WidgetBase {
       '#options' => array(
         'select' => $this->t('Select list'),
         'button' => $this->t('Buttons'),
-        'dropdown' => $this->t('Dropdown button')
+        'dropdown' => $this->t('Dropdown button'),
+        'modal' => $this->t('Modal form'),
       ),
       '#default_value' => $this->getSetting('add_mode'),
       '#required' => TRUE,
@@ -197,6 +198,9 @@ class ParagraphsWidget extends WidgetBase {
       case 'dropdown':
         $add_mode = $this->t('Dropdown button');
         break;
+      case 'modal':
+        $add_mode = $this->t('Modal form');
+        break;
     }
 
     $summary[] = $this->t('Edit mode: @edit_mode', ['@edit_mode' => $edit_mode]);
@@ -229,7 +233,6 @@ class ParagraphsWidget extends WidgetBase {
     $host = $items->getEntity();
     $widget_state = static::getWidgetState($parents, $field_name, $form_state);
 
-    $entity_manager = \Drupal::entityTypeManager();
     $target_type = $this->getFieldSetting('target_type');
 
     $item_mode = isset($widget_state['paragraphs'][$delta]['mode']) ? $widget_state['paragraphs'][$delta]['mode'] : 'edit';
@@ -257,17 +260,6 @@ class ParagraphsWidget extends WidgetBase {
         }
       }
     }
-    elseif (isset($widget_state['selected_bundle'])) {
-
-      $entity_type = $entity_manager->getDefinition($target_type);
-      $bundle_key = $entity_type->getKey('bundle');
-
-      $paragraphs_entity = $entity_manager->getStorage($target_type)->create(array(
-        $bundle_key => $widget_state['selected_bundle'],
-      ));
-
-      $item_mode = 'edit';
-    }
 
     if ($item_mode == 'closed') {
       // Validate closed paragraphs and expand if needed.
@@ -670,6 +662,10 @@ class ParagraphsWidget extends WidgetBase {
       $widget_state['paragraphs'][$delta]['display'] = $display;
       $widget_state['paragraphs'][$delta]['mode'] = $item_mode;
 
+      if ($this->getSetting('add_mode') == 'modal') {
+        $this->buildInBetweenAddButton($element, $id_prefix);
+      }
+
       static::setWidgetState($parents, $field_name, $form_state, $widget_state);
     }
     else {
@@ -680,6 +676,47 @@ class ParagraphsWidget extends WidgetBase {
   }
 
   /**
+   * Builds an add paragraph button between paragraphs for opening of modal.
+   *
+   * @param array $element
+   *   Render element.
+   * @param string $id_prefix
+   *   Prefix.
+   */
+  protected function buildInBetweenAddButton(array &$element, $id_prefix) {
+    if (empty($this->uuid)) {
+      $this->uuid = \Drupal::service('uuid')->generate();
+    }
+
+    $element[$id_prefix . '_area'] = [
+      '#type' => 'container',
+      '#attributes' => [
+        'class' => [
+          'paragraph-type-add-modal',
+          'first-button',
+        ],
+      ],
+      '#access' => !$this->isTranslating,
+      '#weight' => -2000,
+    ];
+
+    $element[$id_prefix . '_area']['add_more'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('+ Add'),
+      '#name' => strtr($id_prefix, '-', '_') . '_add_modal',
+      '#attributes' => [
+        'class' => [
+          'paragraph-type-add-modal-button',
+          'button--small',
+          'js-show',
+        ],
+      ],
+    ];
+
+    $element['#attached']['library'][] = 'paragraphs/drupal.paragraphs.modal';
+  }
+
+  /**
    * Returns the sorted allowed types for a entity reference field.
    *
    * @return array
@@ -828,6 +865,7 @@ class ParagraphsWidget extends WidgetBase {
 
     $field_state = static::getWidgetState($this->fieldParents, $field_name, $form_state);
     $field_state['real_item_count'] = $this->realItemCount;
+    $field_state['add_mode'] = $this->getSetting('add_mode');
     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
 
     $elements += [
@@ -920,7 +958,7 @@ class ParagraphsWidget extends WidgetBase {
         $add_more_elements['info'] = $this->createMessage($this->t('You did not add any @title types yet.', ['@title' => $this->getSetting('title')]));
       }
 
-      return $add_more_elements ;
+      return $add_more_elements;
     }
 
     if ($this->getSetting('add_mode') == 'button' || $this->getSetting('add_mode') == 'dropdown') {
@@ -1096,7 +1134,24 @@ class ParagraphsWidget extends WidgetBase {
   protected function buildSelectAddMode() {
     $field_name = $this->fieldDefinition->getName();
     $title = $this->fieldDefinition->getLabel();
-    $add_more_elements['add_more_select'] = [
+
+    $add_more_elements = [];
+
+    // Add button at end of list, when modal dialog is used to add paragraphs.
+    if ($this->getSetting('add_mode') == 'modal') {
+      $this->buildInBetweenAddButton($add_more_elements, 'first-button');
+
+      // Append template for modal add paragraph dialog.
+      $add_more_elements['paragraphs_add_dialog_template'] = $this->getModalAddDialogTemplate();
+
+      // Selection form elements.
+      $selection_form_elements['add_more_delta'] = [
+        '#type' => 'hidden',
+        '#title' => 'Delta',
+      ];
+    }
+
+    $selection_form_elements['add_more_select'] = [
       '#type' => 'select',
       '#options' => $this->getAccessibleOptions(),
       '#title' => $this->t('@title type', ['@title' => $this->getSetting('title')]),
@@ -1104,12 +1159,11 @@ class ParagraphsWidget extends WidgetBase {
     ];
 
     $text = $this->t('Add @title', ['@title' => $this->getSetting('title')]);
-
     if ($this->realItemCount > 0) {
       $text = $this->t('Add another @title', ['@title' => $this->getSetting('title')]);
     }
 
-    $add_more_elements['add_more_button'] = [
+    $selection_form_elements['add_more_button'] = [
       '#type' => 'submit',
       '#name' => strtr($this->fieldIdPrefix, '-', '_') . '_add_more',
       '#value' => $text,
@@ -1122,8 +1176,19 @@ class ParagraphsWidget extends WidgetBase {
         'effect' => 'fade',
       ],
     ];
+    $selection_form_elements['add_more_button']['#suffix'] = $this->t(' to %type', ['%type' => $title]);
+
+
+    // If we have a modal, the selection form should be hidden.
+    if ($this->getSetting('add_mode') == 'modal') {
+      $add_more_elements['selection_form'] = $selection_form_elements;
+      $add_more_elements['selection_form']['#type'] = 'container';
+      $add_more_elements['selection_form']['#attributes']['class'][] = 'js-hide';
+    }
+    else {
+      $add_more_elements = $selection_form_elements;
+    }
 
-    $add_more_elements['add_more_button']['#suffix'] = $this->t(' to %type', ['%type' => $title]);
     return $add_more_elements;
   }
 
@@ -1134,6 +1199,10 @@ class ParagraphsWidget extends WidgetBase {
     $button = $form_state->getTriggeringElement();
     // Go one level up in the form, to the widgets container.
     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
+    // The structure of modal is different.
+    if (!isset($element['#field_name'])) {
+      $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3));
+    }
 
     // Add a DIV around the delta receiving the Ajax effect.
     $delta = $element['#max_delta'];
@@ -1151,6 +1220,11 @@ class ParagraphsWidget extends WidgetBase {
 
     // Go one level up in the form, to the widgets container.
     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
+    // The structure of modal is different.
+    if (!isset($element['#field_name'])) {
+      $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -3));
+    }
+
     $field_name = $element['#field_name'];
     $parents = $element['#field_parents'];
 
@@ -1159,21 +1233,105 @@ class ParagraphsWidget extends WidgetBase {
 
     if ($widget_state['real_item_count'] < $element['#cardinality'] || $element['#cardinality'] == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
       $widget_state['items_count']++;
+      $widget_state['real_item_count']++;
     }
 
+    $position = $widget_state['real_item_count'] - 1;
     if (isset($button['#bundle_machine_name'])) {
       $widget_state['selected_bundle'] = $button['#bundle_machine_name'];
     }
+    elseif ($widget_state['add_mode'] == 'modal') {
+      $widget_state['selected_bundle'] = $element['add_more']['selection_form']['add_more_select']['#value'];
+      if ($element['add_more']['selection_form']['add_more_delta']['#value'] !== "") {
+        $position = $element['add_more']['selection_form']['add_more_delta']['#value'];
+      }
+    }
     else {
       $widget_state['selected_bundle'] = $element['add_more']['add_more_select']['#value'];
     }
 
+    // Create new paragraph entity.
+    $entity_type = \Drupal::entityTypeManager()->getDefinition('paragraph');
+    $bundle_key = $entity_type->getKey('bundle');
+
+    $paragraphs_entity = \Drupal::entityTypeManager()->getStorage('paragraph')->create(array(
+      $bundle_key => $widget_state['selected_bundle'],
+    ));
+
+    $paragraph = [
+      'entity' => $paragraphs_entity,
+      'mode' => 'edit',
+    ];
+
+    if (isset($widget_state['paragraphs'][$position])) {
+      $paragraph['display'] = $widget_state['paragraphs'][$position]['display'];
+    }
+
+    // Add paragraph to the widget state.
+    // This also creates it, when it doesn't exist.
+    $widget_state['paragraphs'][] = $paragraph;
+
+    // If we use a modal, we have to place the new paragraph
+    // in the correct position.
+    if ($widget_state['add_mode'] == 'modal') {
+      // Clean form_state.
+      $user_input = $user_input_save = $form_state->getUserInput();
+
+      // Temporarily remove 'add_more' from array.
+      unset($user_input[$field_name]['add_more']);
+
+      self::normalizeWeights($user_input[$field_name], $position);
+
+      // It is important, that the key maps with the one from $widget_state
+      // The weight handles the position.
+      $key = count($widget_state['paragraphs']) - 1;
+      $item[$key] = [
+        'subform' => [],
+        '_weight' => $position,
+      ];
+
+      $user_input[$field_name] += $item;
+
+      // Add back 'add_more'.
+      $user_input[$field_name]['add_more'] = $user_input_save[$field_name];
+
+      $form_state->setUserInput($user_input);
+    }
+
     static::setWidgetState($parents, $field_name, $form_state, $widget_state);
 
     $form_state->setRebuild();
   }
 
   /**
+   * This resets the weights, ascending, starting from 0.
+   *
+   * It keeps the indices.
+   *
+   * E.g. [-6, -5, -4] will become [0, 1, 2]
+   *
+   * Starting at position, the elements will get weight+1, to make space
+   * for a new element.
+   *
+   * E.g. [-6, -5, -4], position = 1, will become [ 0,  2,  3]
+   *
+   * @param array $array
+   *   The array, which weights should be normalised.
+   * @param int $position
+   *   The position from which on the weights will be increased by 1.
+   */
+  private static function normalizeWeights(array &$array, $position) {
+    $weigth = 0;
+    foreach ($array as &$value) {
+      if ($weigth == $position) {
+        $weigth++;
+      }
+      $value['_weight'] = $weigth;
+      $weigth++;
+    }
+  }
+
+  /**
    * Creates a duplicate of the paragraph entity.
    */
   public static function duplicateSubmit(array $form, FormStateInterface $form_state) {
@@ -1509,7 +1667,8 @@ class ParagraphsWidget extends WidgetBase {
    * @return int
    *   The number of paragraphs is the given mode.
    */
-  protected function getNumberOfParagraphsInMode(array $widget_state, $mode) {
+  protected function getNumberOfParagraphsInMode(array $widget_state, $mode)
+  {
     if (!isset($widget_state['paragraphs'])) {
       return 0;
     }
@@ -1525,6 +1684,21 @@ class ParagraphsWidget extends WidgetBase {
   }
 
   /**
+   * Returns render array for template of add paragraph modal dialog.
+   *
+   * @return array
+   *   Render array.
+   */
+  protected function getModalAddDialogTemplate() {
+    return [
+      '#theme' => 'paragraphs_add_dialog',
+      '#attached' => [
+        'library' => ['paragraphs/drupal.paragraphs.modal'],
+      ],
+    ];
+  }
+
+  /**
    * {@inheritdoc}
    */
   public static function isApplicable(FieldDefinitionInterface $field_definition) {
diff --git a/templates/paragraphs-add-dialog.html.twig b/templates/paragraphs-add-dialog.html.twig
new file mode 100644
index 0000000..0c7b5e8
--- /dev/null
+++ b/templates/paragraphs-add-dialog.html.twig
@@ -0,0 +1,28 @@
+{#
+/**
+ * @file
+ * Default theme implementation of modal add paragraph dialog template.
+ *
+ * This template for dialog will be handled in javascript, where data-[key]="[attribute]"
+ * attributes will be replaced with data provided for that key. New attribute will be
+ * created like follows: [attribute]="[value-for-key]".
+ *
+ * Following classes have custom use:
+ *   - paragraphs-add-dialog-template - is used to clone dialog.
+ *   - paragraphs-add-dialog-row-template - is used to clone paragraph type rows.
+ *
+ * All listed classes will be renamed in final created dialog with "-template" sufix and
+ * they can be used with that name for theming.
+ *
+ * @ingroup themeable
+ */
+#}
+
+<div class="paragraphs-add-dialog-template" title="{{ 'Add paragraph'|t }}" style="display: none;">
+    <ul class="paragraphs-add-dialog-list">
+        <li class="paragraphs-add-dialog-row-template">
+            <button class="paragraphs-add-type-trigger-element button" data-type-name="content" data-type="data-type"
+                    data-delta="data-delta"></button>
+        </li>
+    </ul>
+</div>
diff --git a/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php b/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php
new file mode 100644
index 0000000..03c7166
--- /dev/null
+++ b/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php
@@ -0,0 +1,232 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\FunctionalJavascript;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\field_ui\Tests\FieldUiTestTrait;
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\node\Entity\NodeType;
+use Drupal\paragraphs\Entity\ParagraphsType;
+use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
+
+/**
+ * Test paragraphs user interface.
+ *
+ * @group paragraphs
+ */
+class ParagraphsAddWidgetTest extends JavascriptTestBase
+{
+
+  use LoginAdminTrait;
+  use FieldUiTestTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'node',
+    'paragraphs_test',
+    'paragraphs',
+    'field',
+    'field_ui',
+    'block',
+    'link',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp()
+  {
+    parent::setUp();
+    // Place the breadcrumb, tested in fieldUIAddNewField().
+    $this->drupalPlaceBlock('system_breadcrumb_block');
+    $this->drupalPlaceBlock('local_tasks_block');
+    $this->drupalPlaceBlock('local_actions_block');
+    $this->drupalPlaceBlock('page_title_block');
+
+  }
+
+
+  /**
+   * Tests the add widget button with modal form.
+   */
+  public function testAddWidgetButton()
+  {
+    $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs');
+    $this->loginAsAdmin([
+      'administer content types',
+      'administer node form display',
+      'edit any paragraphed_test content',
+      'create paragraphed_test content',
+      'administer nodes'
+    ]);
+    $page = $this->getSession()->getPage();
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
+    $page->selectFieldOption('fields[field_paragraphs][type]', 'entity_reference_paragraphs');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $page->pressButton('field_paragraphs_settings_edit');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $edit = [
+      'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
+      'fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'modal'
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Update');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    $this->drupalPostForm(NULL, [], t('Save'));
+
+    // Add a Paragraph type.
+    $paragraph_type = 'text_paragraph';
+    $this->addParagraphsType($paragraph_type);
+    $this->addParagraphsType('text');
+
+    // Add a text field to the text_paragraph type.
+    static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
+
+    // Create paragraph type Nested test.
+    $this->addParagraphsType('nested_test');
+
+    static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_test', 'paragraphs', 'Paragraphs', 'entity_reference_revisions', array(
+      'settings[target_type]' => 'paragraph',
+      'cardinality' => '-1',
+    ), array());
+
+    // Change the add more button to select mode.
+    $this->drupalGet('admin/structure/paragraphs_type/nested_test/form-display');
+    $page->selectFieldOption('fields[field_paragraphs][type]', 'entity_reference_paragraphs');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $page->pressButton('field_paragraphs_settings_edit');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $edit = [
+      'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
+      'fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'modal'
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Update');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $this->drupalPostForm(NULL, [], t('Save'));
+
+    // Add a paragraphed test.
+    $this->drupalGet('node/add/paragraphed_test');
+
+    // Add a nested paragraph with the add widget.
+    $page->pressButton('+ Add');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $page->pressButton('nested_test');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    // Find the add button in the nested paragraph with xpath.
+    $element = $this->xpath('//div[contains(@class, :div-class-1)]/div[contains(@class, :div-class-2)]/input', [
+      ':div-class-1' => 'form-wrapper',
+      ':div-class-2' => 'paragraph-type-add-modal',
+    ]);
+    $element[0]->click();
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    // Add a text inside the nested paragraph.
+    $page->pressButton('text');
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $edit = [
+      'title[0][value]' => 'Example title',
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Save and publish');
+
+    // Check the created paragraphed test.
+    $this->assertText('paragraphed_test Example title has been created.');
+    $this->assertRaw('paragraph--type--nested-test');
+    $this->assertRaw('paragraph--type--text');
+  }
+
+  /**
+   * Adds a content type with a Paragraphs field.
+   *
+   * @param string $content_type_name
+   *   Content type name to be used.
+   * @param string $paragraphs_field_name
+   *   Paragraphs field name to be used.
+   */
+  protected function addParagraphedContentType($content_type_name, $paragraphs_field_name)
+  {
+    // Create the content type.
+    $node_type = NodeType::create([
+      'type' => $content_type_name,
+      'name' => $content_type_name,
+    ]);
+    $node_type->save();
+
+    $this->addParagraphsField($content_type_name, $paragraphs_field_name, 'node');
+  }
+
+  /**
+   * Adds a Paragraphs field to a given $entity_type.
+   *
+   * @param string $entity_type_name
+   *   Entity type name to be used.
+   * @param string $paragraphs_field_name
+   *   Paragraphs field name to be used.
+   * @param string $entity_type
+   *   Entity type where to add the field.
+   */
+  protected function addParagraphsField($entity_type_name, $paragraphs_field_name, $entity_type)
+  {
+    // Add a paragraphs field.
+    $field_storage = FieldStorageConfig::create([
+      'field_name' => $paragraphs_field_name,
+      'entity_type' => $entity_type,
+      'type' => 'entity_reference_revisions',
+      'cardinality' => '-1',
+      'settings' => [
+        'target_type' => 'paragraph',
+      ],
+    ]);
+    $field_storage->save();
+    $field = FieldConfig::create([
+      'field_storage' => $field_storage,
+      'bundle' => $entity_type_name,
+      'settings' => [
+        'handler' => 'default:paragraph',
+        'handler_settings' => ['target_bundles' => NULL],
+      ],
+    ]);
+    $field->save();
+
+    $form_display = EntityFormDisplay::create([
+      'targetEntityType' => $entity_type,
+      'bundle' => $entity_type_name,
+      'mode' => 'default',
+      'status' => TRUE,
+    ])
+      ->setComponent($paragraphs_field_name, ['type' => 'entity_reference_paragraphs']);
+    $form_display->save();
+
+    $view_display = EntityViewDisplay::create([
+      'targetEntityType' => $entity_type,
+      'bundle' => $entity_type_name,
+      'mode' => 'default',
+      'status' => TRUE,
+    ])->setComponent($paragraphs_field_name, ['type' => 'entity_reference_revisions_entity_view']);
+    $view_display->save();
+  }
+
+  /**
+   * Adds a Paragraphs type.
+   *
+   * @param string $paragraphs_type_name
+   *   Paragraph type name used to create.
+   */
+  protected function addParagraphsType($paragraphs_type_name)
+  {
+    $paragraphs_type = ParagraphsType::create([
+      'id' => $paragraphs_type_name,
+      'label' => $paragraphs_type_name,
+    ]);
+    $paragraphs_type->save();
+  }
+}
