diff --git a/facets.libraries.yml b/facets.libraries.yml
index 4e5980e2ea767f427d8f08e327208a40afb6313c..643be6fd0f1582383df4748f8f7bf34ffe198eca 100644
--- a/facets.libraries.yml
+++ b/facets.libraries.yml
@@ -38,3 +38,11 @@ drupal.facets.dropdown-widget:
     - core/jquery
     - core/drupal
     - core/jquery.once
+soft-limit:
+  version: VERSION
+  js:
+    js/soft-limit.js: {}
+  dependencies:
+    - core/jquery
+    - core/jquery.once
+    - core/drupalSettings
diff --git a/js/checkbox-widget.js b/js/checkbox-widget.js
index 997aaca74efaa11ba0c2bb2edb1bec25c58db61a..ff04ea6e874313080b5aaafa342b259e7c307075 100644
--- a/js/checkbox-widget.js
+++ b/js/checkbox-widget.js
@@ -7,7 +7,7 @@
 
   "use strict";
 
-  Drupal.facets = {};
+  Drupal.facets = Drupal.facets || {};
   Drupal.behaviors.facetsCheckboxWidget = {
     attach: function (context, settings) {
       Drupal.facets.makeCheckboxes();
@@ -31,7 +31,7 @@
     var active = $link.hasClass('is-active');
     var description = $link.html();
     var href = $link.attr('href');
-    var id = $link.data('facet-id');
+    var id = $link.data('drupal-facet-item-id');
 
     var checkbox = $('<input type="checkbox" class="facets-checkbox" id="' + id + '" data-facetsredir="' + href + '" />');
     var label = $('<label for="' + id + '">' + description + '</label>');
diff --git a/js/soft-limit.js b/js/soft-limit.js
new file mode 100644
index 0000000000000000000000000000000000000000..d639e29c001f6c1088349a55a4a2a2954936d6ba
--- /dev/null
+++ b/js/soft-limit.js
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * Provides the soft limit functionality.
+ */
+
+(function ($) {
+
+  "use strict";
+
+  Drupal.behaviors.facetSoftLimit = {
+    attach: function (context, settings) {
+      if (settings.facets.softLimit != undefined) {
+        $.each(settings.facets.softLimit, function (facet, limit) {
+          Drupal.facets.applySoftLimit(facet, limit);
+        })
+      }
+    }
+  };
+
+  Drupal.facets = Drupal.facets || {};
+
+  /**
+   * Applies the soft limit UI feature to a specific facets list.
+   */
+  Drupal.facets.applySoftLimit = function (facet, limit) {
+    var zero_based_limit = limit - 1;
+    var facetsList = $('ul[data-drupal-facet-id="' + facet + '"]');
+
+    // Hide facets over the limit.
+    facetsList.find('li:gt(' + zero_based_limit + ')').once().hide();
+
+    // Add "Show more" / "Show less" links.
+    facetsList.once().filter(function() {
+      return $(this).find('li').length > limit;
+    }).each(function() {
+      $('<a href="#" class="facets-soft-limit-link"></a>').text(Drupal.t('Show more')).click(function() {
+        if ($(this).siblings().find('li:hidden').length > 0) {
+          $(this).siblings().find('li:gt(' + zero_based_limit + ')').slideDown();
+          $(this).addClass('open').text(Drupal.t('Show less'));
+        }
+        else {
+          $(this).siblings().find('li:gt(' + zero_based_limit + ')').slideUp();
+          $(this).removeClass('open').text(Drupal.t('Show more'));
+        }
+        return false;
+      }).insertAfter($(this));
+    });
+  };
+
+})(jQuery);
diff --git a/src/FacetManager/DefaultFacetManager.php b/src/FacetManager/DefaultFacetManager.php
index dd9e30c90fdc2fba8311106b35fd5e43bae48cb3..a044f6ba2315b1acada4b42359051f8e2dd71790 100644
--- a/src/FacetManager/DefaultFacetManager.php
+++ b/src/FacetManager/DefaultFacetManager.php
@@ -327,7 +327,7 @@ class DefaultFacetManager {
     if (empty($facet->getResults())) {
       $empty_behavior = $facet->getEmptyBehavior();
       if ($empty_behavior['behavior'] == 'text') {
-        return ['#markup' => $empty_behavior['text']];
+        return [['#markup' => $empty_behavior['text']]];
       }
       else {
         return [];
@@ -338,7 +338,7 @@ class DefaultFacetManager {
     /** @var \Drupal\facets\Widget\WidgetInterface $widget */
     $widget = $this->widgetPluginManager->createInstance($facet->getWidget());
 
-    return $widget->build($facet);
+    return [$widget->build($facet)];
   }
 
   /**
diff --git a/src/Plugin/facets/widget/CheckboxWidget.php b/src/Plugin/facets/widget/CheckboxWidget.php
index b22b4aa82f981e585e3f557560c6bb7a6b1ff59b..02fbae6bc8b6afab67f104f048c9ca439b2f02cc 100644
--- a/src/Plugin/facets/widget/CheckboxWidget.php
+++ b/src/Plugin/facets/widget/CheckboxWidget.php
@@ -28,35 +28,8 @@ class CheckboxWidget extends LinksWidget {
    */
   public function build(FacetInterface $facet) {
     $this->facet = $facet;
-
-    /** @var \Drupal\facets\Result\Result[] $results */
-    $results = $facet->getResults();
-    $items = [];
-
-    $configuration = $facet->getWidgetConfigs();
-    $this->showNumbers = empty($configuration['show_numbers']) ? FALSE : (bool) $configuration['show_numbers'];
-
-    foreach ($results as $result) {
-      if (is_null($result->getUrl())) {
-        $text = $this->extractText($result);
-        $items[] = ['#markup' => $text];
-      }
-      else {
-        $items[] = $this->buildListItems($result);
-      }
-    }
-
-    $build = [
-      '#theme' => 'item_list',
-      '#items' => $items,
-      '#attributes' => ['class' => ['js-facets-checkbox-links']],
-      '#cache' => [
-        'contexts' => [
-          'url.path',
-          'url.query_args',
-        ],
-      ],
-    ];
+    $build = parent::build($facet);
+    $build['#attributes']['class'][] = 'js-facets-checkbox-links';
     $build['#attached']['library'][] = 'facets/drupal.facets.checkbox-widget';
 
     return $build;
@@ -67,7 +40,7 @@ class CheckboxWidget extends LinksWidget {
    */
   protected function buildListItems(ResultInterface $result) {
     $items = parent::buildListItems($result);
-    $items['#attributes']['data-facet-id'] = $this->facet->getUrlAlias() . '-' . $result->getRawValue();
+    $items['#attributes']['data-drupal-facet-item-id'] = $this->facet->getUrlAlias() . '-' . $result->getRawValue();
     return $items;
   }
 
diff --git a/src/Plugin/facets/widget/LinksWidget.php b/src/Plugin/facets/widget/LinksWidget.php
index 31db9ee8368c5089dae8dbab8d98ee9edafac20e..b7ae07dfa5f91e918af75ec6ea9baecaf91e06f9 100644
--- a/src/Plugin/facets/widget/LinksWidget.php
+++ b/src/Plugin/facets/widget/LinksWidget.php
@@ -54,6 +54,7 @@ class LinksWidget implements WidgetInterface {
     $build = [
       '#theme' => 'item_list',
       '#items' => $items,
+      '#attributes' => ['data-drupal-facet-id' => $facet->id()],
       '#cache' => [
         'contexts' => [
           'url.path',
@@ -61,6 +62,12 @@ class LinksWidget implements WidgetInterface {
         ],
       ],
     ];
+
+    if (!empty($configuration['soft_limit'])) {
+      $build['#attached']['library'][] = 'facets/soft-limit';
+      $build['#attached']['drupalSettings']['facets']['softLimit'][$facet->id()] = (int) $configuration['soft_limit'];
+    }
+
     return $build;
   }
 
@@ -155,20 +162,30 @@ class LinksWidget implements WidgetInterface {
 
   /**
    * {@inheritdoc}
+   *
+   * @todo This is inheriting nothing. We need a method on the interface and,
+   *   probably, a base class.
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state, $config) {
+    $widget_configs = !is_null($config) ? $config->get('widget_configs') : [];
+    // Assure sane defaults.
+    // @todo This should be handled upstream, in facet entity. Facet schema
+    //   should be fixed and all configs should get sane defaults.
+    $widget_configs += ['show_numbers' => FALSE, 'soft_limit' => 0];
 
     $form['show_numbers'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Show the amount of results'),
+      '#default_value' => $widget_configs['show_numbers'],
+    ];
+    $options = [50, 40, 30, 20, 15, 10, 5, 3];
+    $form['soft_limit'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Soft limit'),
+      '#default_value' => $widget_configs['soft_limit'],
+      '#options' => [0 => $this->t('No limit')] + array_combine($options, $options),
+      '#description' => $this->t('Limits the number of displayed facets via JavaScript.'),
     ];
-
-    if (!is_null($config)) {
-      $widget_configs = $config->get('widget_configs');
-      if (isset($widget_configs['show_numbers'])) {
-        $form['show_numbers']['#default_value'] = $widget_configs['show_numbers'];
-      }
-    }
 
     return $form;
   }