diff --git a/images/collapsed.png b/images/collapsed.png
new file mode 100644
index 0000000000000000000000000000000000000000..91f3fd40ede024798b6de5ea2675bb692a3cfa95
GIT binary patch
literal 105
zcmeAS@N?(olHy`uVBq!ia0vp^>>$j@3?%=}IXVGIu?6^qxc>kDAIJ<nbh!>lF_r}R
y1v5B2yO9Ru2zt6WhH%Ixhb6Q*Xr>9K@iDN~Fr3*g^XWQJlEKr}&t;ucLK6T5e;aZD

literal 0
HcmV?d00001

diff --git a/images/expanded.png b/images/expanded.png
new file mode 100644
index 0000000000000000000000000000000000000000..46f39ecb351cff65243fa9a614a69d039e1302a5
GIT binary patch
literal 106
zcmeAS@N?(olHy`uVBq!ia0vp^>>$j@3?%=}IXVGIu?6^qxc>kDAIJ<nbh!>lF_r}R
z1v5B2yO9Ru2zk0VhE&W+{&76uaKb@_0}N~oA{!VF-#vS9IZ&3t)78&qol`;+0EMF;
ATL1t6

literal 0
HcmV?d00001

diff --git a/paragraphs.collapsible.css b/paragraphs.collapsible.css
new file mode 100644
index 0000000000000000000000000000000000000000..a90e117b2e4ab356d04716af14e8dedb4d8deb7f
--- /dev/null
+++ b/paragraphs.collapsible.css
@@ -0,0 +1,14 @@
+/**
+ * Admin CSS styles for the paragraphs module.
+ */
+
+td.paragraph-bundle-content-collapsible .paragraph-bundle-title {
+  cursor: pointer;
+  background: url(images/expanded.png) 5px 65% no-repeat; /* LTR */
+  padding-left: 15px; /* LTR */
+}
+
+td.paragraph-bundle-content-collapsible.collapsed .paragraph-bundle-title {
+  background-image: url(images/collapsed.png); /* LTR */
+  background-position: 5px 50%; /* LTR */
+}
diff --git a/paragraphs.collapsible.js b/paragraphs.collapsible.js
new file mode 100644
index 0000000000000000000000000000000000000000..c44ec20b9581a4c5fa410c4871815994b1b9910c
--- /dev/null
+++ b/paragraphs.collapsible.js
@@ -0,0 +1,242 @@
+/**
+ * @file
+ * Provides JavaScript for Collapsible Paragraphs.
+ */
+
+(function ($, Drupal, window) {
+  // Stored variables.
+  var mToolbarHeight = null;
+
+  /**
+   * Show / Hide a single paragraph.
+   *
+   * @param object item
+   *   The element of the field item row.
+   * @param string action
+   *   The toggle action - 'collapse' or 'expand'.
+   * @param object options
+   *   A set of options to configure the toggle:
+   *   - excludeNew (bool): TRUE to exclude operating on new AJAX content.
+   *   - excludeErrors (bool): TRUE to exclude operating on items with errors.
+   *   - fx (object): Options for the slide effects.
+   *
+   * @return boolean
+   *   TRUE if the paragraph was toggled,
+   */
+  var toggleParagraph = function(item, action, options) {
+    var $item = $(item);
+    var elements;
+
+    var settings = $.extend(true,
+      {
+        'excludeNew': false,
+        'excludeErrors': false,
+        'fx': {
+          duration: 'fast',
+          easing: 'linear'
+        }
+      },
+      options
+    );
+
+    // Except the first div, show/hide others.
+    var $ajax_content = $item.children('.ajax-new-content');
+    if ($ajax_content.length > 0) {
+      // Exit if excluding new content.
+      if (settings.excludeNew) {
+        return false;
+      }
+      elements = $ajax_content.children(':not(.paragraph-bundle-title, .paragraph-bundle-preview), fieldset');
+    }
+    else {
+      elements = $item.children(':not(.paragraph-bundle-title, .paragraph-bundle-preview), fieldset');
+    }
+
+    // Do not collapse deleted paragraphs.
+    if (action === 'collapse' && elements.filter('.form-actions').find('[name$="deleteconfirm_button"]').length > 0) {
+      return false;
+    }
+
+    // Exclude errors.
+    if (settings.excludeErrors && elements.find('.error').length > 0) {
+      return false;
+    }
+
+    // Invoke collapse actions.
+    if (action === 'collapse') {
+      elements.slideUp(settings.fx);
+      $item
+        .removeClass('expanded').addClass('collapsed')
+        .find('> .paragraph-bundle-title > .paragraph-bundle-title-collapsible-prefix').html(Drupal.t('Show'));
+    }
+    else {
+      elements.slideDown(settings.fx);
+      $item
+        .removeClass('collapsed').addClass('expanded')
+        .find('> .paragraph-bundle-title > .paragraph-bundle-title-collapsible-prefix').html(Drupal.t('Hide'));
+    }
+
+    return true;
+  };
+
+  /**
+   * Show / Hide all paragraphs.
+   *
+   * @param object triggerElement
+   *   The trigger element to toggle all child paragraphs.
+   * @param string action
+   *   The toggle action - 'collapse' or 'expand'.
+   * @param object options
+   *   See toggleParagraph().
+   *
+   * @return int
+   *   The count of paragraphs toggled.
+   */
+  var toggleParagraphs = function(triggerElement, action, options) {
+    var toggledCount = 0;
+    var $form_item = $(triggerElement).closest('.form-item');
+    if ($form_item.length > 0) {
+      var paragraph_bundles = $form_item.children('.field-multiple-table').find('.paragraph-bundle-content-collapsible');
+      paragraph_bundles.each(function () {
+        if (toggleParagraph(this, action, options)) {
+          toggledCount++;
+        }
+      });
+    }
+
+    return toggledCount;
+  };
+
+  /**
+   * Trigger show / hide for given trigger element.
+   *
+   * @param object triggerElement
+   *   The trigger element to toggle all child paragraphs.
+   * @param object options
+   *   See toggleParagraph().
+   *
+   * @return int
+   *   The count of paragraphs toggled.
+   */
+  var toggleAll = function(triggerElement, options) {
+    var $t = $(triggerElement);
+
+    // Build triggers.
+    var $triggers = [$t];
+
+    // Add other trigger.
+    var $parent_table = $t.closest('table');
+    if ($parent_table.length > 0) {
+      if ($parent_table.hasClass('field-multiple-table')) {
+        // Items table click, add sticky header trigger.
+        $triggers.push($parent_table.siblings('.sticky-header').find('.paragraphs-collapsible-trigger-link'));
+      }
+      else if ($parent_table.hasClass('sticky-header')) {
+        // Sticky header click, add items table click.
+        $triggers.push($parent_table.siblings('table.field-multiple-table').find('.paragraphs-collapsible-trigger-link'));
+      }
+    }
+
+    var action = $t.hasClass('collapsed') ? 'expand' : 'collapse';
+    var toggledCount = toggleParagraphs(triggerElement, action, options);
+    if (toggledCount > 0) {
+      $.each($triggers, function(index, $trigger) {
+        if ($trigger.length > 0) {
+          if (action === 'expand') {
+            $trigger.removeClass('collapsed').addClass('expanded');
+            $trigger.text(Drupal.t('Collapse All'));
+          }
+          else {
+            $trigger.removeClass('expanded').addClass('collapsed');
+            $trigger.text(Drupal.t('Expand All'));
+          }
+        }
+      });
+    }
+
+    return toggledCount;
+  };
+
+  /**
+   * Scroll a given fieldset into view as much as possible.
+   */
+  var collapseScrollIntoView = function(element) {
+    var $element = $(element).first();
+    var offset = $element.offset();
+    var slack = 55;
+
+    if (offset.top > 0) {
+      if (mToolbarHeight === null) {
+        mToolbarHeight = $('#toolbar').outerHeight() || 0;
+      }
+      var y = Math.floor(offset.top - mToolbarHeight - slack);
+      y = y > 0 ? y : 0;
+      $(window).scrollTop(y);
+    }
+  };
+
+  /**
+   * Enable Expand/Collapse feature for paragraph bundles.
+   * Show the name & type of each bundle and hide contents inside those.
+   */
+  Drupal.behaviors.paragraphsCollapsible = {
+    attach: function (context, settings) {
+      // Trigger for single paragaph.
+      $('.paragraph-bundle-content-collapsible > .paragraph-bundle-title, .paragraph-bundle-content-collapsible > .ajax-new-content > .paragraph-bundle-title', context)
+        .once("paragraphs")
+          .each(function() {
+            var $t = $(this);
+            var $item = $t.closest('.paragraph-bundle-content-collapsible');
+
+            // Prefix title with a toggle image.
+            $('<span class="paragraph-bundle-title-collapsible-prefix element-invisible"></span>')
+                .append($item.hasClass('expanded') ? Drupal.t('Hide') : Drupal.t('Show'))
+                .prependTo($t)
+                .after(' ');
+          })
+          .click(function(event) {
+            // Prevent the default click event.
+            event.preventDefault();
+            var $item = $(this).closest('.paragraph-bundle-content-collapsible');
+            if ($item.length) {
+              var action = $item.hasClass('collapsed') ? 'expand' : 'collapse';
+              toggleParagraph($item, action);
+            }
+          });
+
+      // Trigger for all paragaphs.
+      $('.paragraphs-collapsible-trigger-link', context).once("paragraphs")
+        .click(function(event) {
+          // Prevent the default click event.
+          event.preventDefault();
+          toggleAll(this);
+        })
+        .filter('.paragraphs-collapsible-init-collapsed')
+          .filter(':not(.collapsed)').each(function() {
+            // Initial collapse processing.
+            var $t = $(this);
+
+            // If parent table is field item table - not the sticky header table
+            // or a parent field item's table when using nested paragraphs.
+            var $table = $t.closest('table').filter('.field-multiple-table')
+            if ($table.length > 0) {
+              var toggleOptions = {'excludeNew': true, 'excludeErrors': true};
+
+              // Scroll to new content after other paragraphs get collapsed.
+              var $newContent = $('.paragraph-bundle-content > .ajax-new-content', $table)
+              if ($newContent.length > 0) {
+                toggleOptions.fx = {
+                  complete: function() {
+                    collapseScrollIntoView($newContent);
+                  }
+                }
+              }
+
+              // Collapse all paragraphs.
+              toggleAll($t, toggleOptions);
+            }
+          });
+    }
+  };
+
+})(jQuery, Drupal, this);
diff --git a/paragraphs.field_widget.inc b/paragraphs.field_widget.inc
index 921843c5da4730328349ca02bfb042ec23251261..617c26f68ef5f4ac810857ba2d566ee179177425 100644
--- a/paragraphs.field_widget.inc
+++ b/paragraphs.field_widget.inc
@@ -345,6 +345,14 @@ function paragraphs_field_widget_form_build(&$form, &$form_state, $field, $insta
     $instance['settings']['title_multiple'] = PARAGRAPHS_DEFAULT_TITLE_MULTIPLE;
   }
 
+  if (!isset($instance['settings']['open_collapsible'])) {
+    $instance['settings']['open_collapsible'] = PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE;
+  }
+
+  if (!isset($instance['settings']['open_collapsible_preview'])) {
+    $instance['settings']['open_collapsible_preview'] = PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_PREVIEW;
+  }
+
   // If the paragraph item form contains another paragraph,
   // we might ran into a recursive loop. Prevent that.
   if ($recursion++ > PARAGRAPHS_RECURSION_LIMIT) {
@@ -445,6 +453,7 @@ function paragraphs_field_widget_form_build(&$form, &$form_state, $field, $insta
       $element['paragraph_bundle_title'] = array(
         '#type' => 'container',
         '#weight' => -100,
+        '#attributes' => array('class' => array('paragraph-bundle-title')),
       );
       $element['paragraph_bundle_title']['info'] = array(
         '#markup' => t('!title type: %bundle', array('!title' => t($instance['settings']['title']), '%bundle' => $bundle_info->name)),
@@ -503,6 +512,7 @@ function paragraphs_field_widget_form_build(&$form, &$form_state, $field, $insta
         if($default_edit_mode === 'preview' && entity_access('view', 'paragraphs_item', $paragraph_item)) {
           $element['paragraph_bundle_preview'] = array(
             '#type' => 'container',
+            '#attributes' => array('class' => array('paragraph-bundle-preview')),
           );
           $preview = $paragraph_item->view('paragraphs_editor_preview');
           $element['paragraph_bundle_preview']['preview'] = $preview;
@@ -542,6 +552,24 @@ function paragraphs_field_widget_form_build(&$form, &$form_state, $field, $insta
         );
       }
 
+      // Collapsible open paragraphs.
+      if ($default_edit_mode == 'open' && !empty($instance['settings']['open_collapsible'])) {
+        // Attach js and css.
+        $element['#attached']['js'][] = drupal_get_path('module', 'paragraphs') . '/paragraphs.collapsible.js';
+        $element['#attached']['css'][] = drupal_get_path('module', 'paragraphs') . '/paragraphs.collapsible.css';
+
+        // Build preview.
+        if (!empty($instance['settings']['open_collapsible_preview']) &&
+            !isset($element['paragraph_bundle_preview']) &&
+            isset($paragraph_item) && entity_access('view', 'paragraphs_item', $paragraph_item)) {
+          $element['paragraph_bundle_preview'] = array(
+            '#type' => 'container',
+            '#attributes' => array('class' => array('paragraph-bundle-preview')),
+          );
+          $preview = $paragraph_item->view('paragraphs_editor_preview');
+          $element['paragraph_bundle_preview']['preview'] = $preview;
+        }
+      }
 
       if (isset($paragraph_item)) {
         $element['actions']['remove_button'] = array(
diff --git a/paragraphs.module b/paragraphs.module
index 47093b6ca57d217ea0c88b6491dc3d4fa1447600..de86f467e6e9ec2e290fa8f1c37962fe40056227 100644
--- a/paragraphs.module
+++ b/paragraphs.module
@@ -11,6 +11,9 @@ define('PARAGRAPHS_DEFAULT_TITLE_MULTIPLE', 'Paragraphs');
 define('PARAGRAPHS_DEFAULT_EDIT_MODE', 'open');
 define('PARAGRAPHS_DEFAULT_EDIT_MODE_OVERRIDE', 1);
 define('PARAGRAPHS_DEFAULT_ADD_MODE', 'select');
+define('PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE', TRUE);
+define('PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_COLLAPSED', TRUE);
+define('PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_PREVIEW', FALSE);
 
 /**
  * Modules should return this value from hook_paragraphs_item_access() to allow access to a paragraphs item.
@@ -431,6 +434,9 @@ function paragraphs_field_info() {
       'title_multiple' => PARAGRAPHS_DEFAULT_TITLE_MULTIPLE,
       'allowed_bundles' => array(),
       'bundle_weights' => array(),
+      'open_collapsible' => PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE,
+      'open_collapsible_collapsed' => PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_COLLAPSED,
+      'open_collapsible_preview' => PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_PREVIEW,
     ),
     'default_widget' => 'paragraphs_hidden',
     'default_formatter' => 'paragraphs_view',
@@ -593,6 +599,48 @@ function paragraphs_field_instance_settings_form($field, $instance) {
     '#required' => TRUE,
   );
 
+  $element['open_collapsible'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable collapsible form items'),
+    '#description' => t('Provides client-side collapsible paragraphs via JavaScript.'),
+    '#default_value' => isset($settings['open_collapsible']) ? $settings['open_collapsible'] : PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE,
+    '#states' => array(
+      // Show the settings when the default edit mode is set to "Open".
+      'visible' => array(
+        ':input[name="instance[settings][default_edit_mode]"]' => array('value' => 'open'),
+      ),
+    ),
+  );
+
+  $element['open_collapsible_collapsed'] = array(
+    '#type' => 'checkbox',
+    '#field_prefix' => '<span>&nbsp;&nbsp;&nbsp; </span>',
+    '#title' => t('Collapse all paragraphs initially'),
+    '#default_value' => isset($settings['open_collapsible_collapsed']) ? $settings['open_collapsible_collapsed'] : PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_COLLAPSED,
+    '#states' => array(
+      // Show the settings when open_collapsible is enabled.
+      'visible' => array(
+        ':input[name="instance[settings][default_edit_mode]"]' => array('value' => 'open'),
+        ':input[name="instance[settings][open_collapsible]"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+
+  $element['open_collapsible_preview'] = array(
+    '#type' => 'checkbox',
+    '#field_prefix' => '<span>&nbsp;&nbsp;&nbsp; </span>',
+    '#title' => t('Display paragraphs preview view mode for collapsible items'),
+    '#description' => t('This will display the rendered preview with the stored values when the form is built.  This does not attempt to update the preview as values are changed.'),
+    '#default_value' => isset($settings['open_collapsible_preview']) ? $settings['open_collapsible_preview'] : PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_PREVIEW,
+    '#states' => array(
+      // Show the settings when open_collapsible is enabled.
+      'visible' => array(
+        ':input[name="instance[settings][default_edit_mode]"]' => array('value' => 'open'),
+        ':input[name="instance[settings][open_collapsible]"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+
   if (!count($bundles)) {
     $element['allowed_bundles_explain'] = array(
       '#type' => 'markup',
@@ -1154,11 +1202,41 @@ function theme_paragraphs_field_multiple_value_form($variables) {
   if (!isset($instance['settings']['title_multiple'])) {
     $instance['settings']['title_multiple'] = PARAGRAPHS_DEFAULT_TITLE_MULTIPLE;
   }
+  if (!isset($instance['settings']['open_collapsible'])) {
+    $instance['settings']['open_collapsible'] = PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE;
+  }
+  if (!isset($instance['settings']['open_collapsible_collapsed'])) {
+    $instance['settings']['open_collapsible_collapsed'] = PARAGRAPHS_DEFAULT_OPEN_COLLAPSIBLE_COLLAPSED;
+  }
 
   $add_mode = (isset($instance['settings']['add_mode']) ? $instance['settings']['add_mode'] : PARAGRAPHS_DEFAULT_ADD_MODE);
+  $default_edit_mode = isset($instance['settings']['default_edit_mode']) ? $instance['settings']['default_edit_mode'] : PARAGRAPHS_DEFAULT_EDIT_MODE;
 
   $required = !empty($element['#required']) ? theme('form_required_marker', $variables) : '';
 
+  // Open collapsible processing.
+  $open_collapsible_enabled = FALSE;
+  $expand_collapse_markup = '';
+  if ($default_edit_mode == 'open' && !empty($instance['settings']['open_collapsible'])) {
+    $open_collapsible_enabled = TRUE;
+    $expand_collapse_link_classes = array(
+      'paragraphs-collapsible-trigger-link',
+      'expanded',
+    );
+    if (!empty($instance['settings']['open_collapsible_collapsed'])) {
+      $expand_collapse_link_classes[] = 'paragraphs-collapsible-init-collapsed';
+    }
+
+    $expand_collapse_markup = '<span style="float: right" class="paragraphs-collapsible-trigger">';
+    $expand_collapse_markup .= l(t('Collapse All'), '#', array(
+      'external' => TRUE,
+      'attributes' => array(
+        'class' => $expand_collapse_link_classes,
+      ),
+    ));
+    $expand_collapse_markup .= '</span>';
+  }
+
   // Sort items according to '_weight' (needed when the form comes back after
   // preview or failed validation)
   $items = array();
@@ -1182,9 +1260,23 @@ function theme_paragraphs_field_multiple_value_form($variables) {
     $table_id = drupal_html_id($element['#field_name'] . '_values');
     $order_class = $element['#field_name'] . '-delta-order';
 
+    if ($open_collapsible_enabled) {
+      $header_text = t('!title !required !collapsible', array(
+        '!collapsible' => $expand_collapse_markup,
+        '!title' => $element['#title'],
+        '!required' => $required,
+      ));
+    }
+    else {
+      $header_text = t('!title !required', array(
+        '!title' => $element['#title'],
+        '!required' => $required,
+      ));
+    }
+
     $header = array(
       array(
-        'data' => '<label>' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . '</label>',
+        'data' => '<label>' . $header_text . '</label>',
         'colspan' => 2,
         'class' => array('field-label'),
       ),
@@ -1193,12 +1285,17 @@ function theme_paragraphs_field_multiple_value_form($variables) {
     $rows = array();
 
     // Add the items as table rows.
+    $item_classes = array('paragraph-bundle-content');
+    if ($open_collapsible_enabled) {
+      $item_classes[] = 'paragraph-bundle-content-collapsible';
+      $item_classes[] = 'expanded';
+    }
     foreach ($items as $key => $item) {
       $item['_weight']['#attributes']['class'] = array($order_class);
       $delta_element = drupal_render($item['_weight']);
       $cells = array(
         array('data' => '', 'class' => array('field-multiple-drag')),
-        drupal_render($item),
+        array('data' => drupal_render($item), 'class' => $item_classes),
         array('data' => $delta_element, 'class' => array('delta-order')),
       );
       $rows[] = array(
@@ -1454,4 +1551,4 @@ function paragraphs_modules_uninstalled($modules) {
   if (in_array('entitycache', $modules)) {
     paragraphs_remove_entitycache_table();
   }
-}
\ No newline at end of file
+}
