diff --git a/facets.module b/facets.module
index 17ee3c9..b3eedbf 100644
--- a/facets.module
+++ b/facets.module
@@ -71,6 +71,15 @@ function facets_theme($existing, $type, $theme, $path) {
   ];
 }
 
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function facets_theme_suggestions_facets_result_item(array $variables) {
+  $widget = $variables['facet']->getWidget();
+  $suggestions[] = 'facets_result_item__' . $widget['type'];
+  return $suggestions;
+}
+
 /**
  * Implements hook_search_api_query_alter().
  */
diff --git a/js/checkbox-widget.js b/js/checkbox-widget.js
index 154c54b..fb0ce09 100644
--- a/js/checkbox-widget.js
+++ b/js/checkbox-widget.js
@@ -10,49 +10,21 @@
   Drupal.facets = Drupal.facets || {};
   Drupal.behaviors.facetsCheckboxWidget = {
     attach: function (context, settings) {
-      Drupal.facets.makeCheckboxes();
+      // Find all checkbox facet links and give them a checkbox.
+      var $checkboxes = $('.js-facets-checkbox-links input:checkbox', context);
+      $checkboxes.once('facets-checkbox-transform').each(Drupal.facets.addCheckboxChangeListener);
     }
   };
 
   /**
-   * Turns all facet links into checkboxes.
+   * Add event listener to the change event of the checkboxes to navigate to the correct url.
    */
-  Drupal.facets.makeCheckboxes = function () {
-    // Find all checkbox facet links and give them a checkbox.
-    var $links = $('.js-facets-checkbox-links .facet-item a');
-    $links.once('facets-checkbox-transform').each(Drupal.facets.makeCheckbox);
-    // Set indeterminate value on parents having an active trail.
-    $('.facet-item--expanded.facet-item--active-trail > input').prop('indeterminate', true);
-  };
-
-  /**
-   * Replace a link with a checked checkbox.
-   */
-  Drupal.facets.makeCheckbox = function () {
-    var $link = $(this);
-    var active = $link.hasClass('is-active');
-    var description = $link.html();
-    var href = $link.attr('href');
-    var id = $link.data('drupal-facet-item-id');
-
-    var checkbox = $('<input type="checkbox" class="facets-checkbox">')
-      .attr('id', id)
-      .data($link.data())
-      .data('facetsredir', href);
-    var label = $('<label for="' + id + '">' + description + '</label>');
-
-    checkbox.on('change.facets', function (e) {
-      Drupal.facets.disableFacet($link.parents('.js-facets-checkbox-links'));
-      window.location.href = $(this).data('facetsredir');
+  Drupal.facets.addCheckboxChangeListener = function () {
+    var $checkbox = $(this);
+    $checkbox.on('change.facets', function (e) {
+      Drupal.facets.disableCheckboxFacet($checkbox.parents('.js-facets-checkbox-links'));
+      window.location.href = $(this).val();
     });
-
-    if (active) {
-      checkbox.attr('checked', true);
-      label.find('.js-facet-deactivate').remove();
-    }
-
-    $link.before(checkbox).before(label).remove();
-
   };
 
   /**
@@ -61,10 +33,11 @@
    * @param {object} $facet
    *   jQuery object of the facet.
    */
-  Drupal.facets.disableFacet = function ($facet) {
-    $facet.addClass('facets-disabled');
-    $('input.facets-checkbox').click(Drupal.facets.preventDefault);
-    $('input.facetapi-checkbox', $facet).attr('disabled', true);
+  Drupal.facets.disableCheckboxFacet = function ($facet) {
+    $facet.addClass('facets-disabled form-disabled');
+    var $checkboxes = $('.js-facets-checkbox-links input:checkbox');
+    $checkboxes.click(Drupal.facets.preventDefault);
+    $checkboxes.attr('disabled', true);
   };
 
   /**
diff --git a/js/dropdown-widget.js b/js/dropdown-widget.js
index e87b929..1b64ee8 100644
--- a/js/dropdown-widget.js
+++ b/js/dropdown-widget.js
@@ -10,75 +10,23 @@
   Drupal.facets = Drupal.facets || {};
   Drupal.behaviors.facetsDropdownWidget = {
     attach: function (context, settings) {
-      Drupal.facets.makeDropdown(context, settings);
+      // Find all dropdown facet links and turn them into an option.
+      $('select.js-facets-dropdown-links').once('facets-dropdown-change').each(Drupal.facets.addDropdownChangeListener);
     }
   };
 
   /**
-   * Turns all facet links into a dropdown with options for every link.
+   * Add event listener to the change event of the dropdown to navigate to the correct url.
    *
    * @param {object} context
    *   Context.
    * @param {object} settings
    *   Settings.
    */
-  Drupal.facets.makeDropdown = function (context, settings) {
-    // Find all dropdown facet links and turn them into an option.
-    $('.js-facets-dropdown-links').once('facets-dropdown-transform').each(function () {
-      var $ul = $(this);
-      var $links = $ul.find('.facet-item a');
-      var $dropdown = $('<select />');
-      // Preserve all attributes of the list.
-      $ul.each(function() {
-        $.each(this.attributes,function(idx, elem) {
-            $dropdown.attr(elem.name, elem.value);
-        });
-      });
-      // Remove the class which we are using for .once().
-      $dropdown.removeClass('js-facets-dropdown-links');
-
-      $dropdown.addClass('facets-dropdown');
-
-      var id = $(this).data('drupal-facet-id');
-      var default_option_label = settings.facets.dropdown_widget[id]['facet-default-option-label'];
-      // Add empty text option first.
-      var $default_option = $('<option />')
-        .attr('value', '')
-        .text(default_option_label);
-      $dropdown.append($default_option);
-
-      var has_active = false;
-      $links.each(function () {
-        var $link = $(this);
-        var active = $link.hasClass('is-active');
-        var $option = $('<option />')
-          .attr('value', $link.attr('href'))
-          .data($link.data());
-        if (active) {
-          has_active = true;
-          // Set empty text value to this link to unselect facet.
-          $default_option.attr('value', $link.attr('href'));
-
-          $option.attr('selected', 'selected');
-          $link.find('.js-facet-deactivate').remove();
-        }
-        $option.html($link.text());
-        $dropdown.append($option);
-      });
-
-      // Go to the selected option when it's clicked.
-      $dropdown.on('change.facets', function () {
-        window.location.href = $(this).val();
-      });
-
-      // Append empty text option.
-      if (!has_active) {
-        $default_option.attr('selected', 'selected');
-      }
-
-      // Replace links with dropdown.
-      $ul.after($dropdown).remove();
-      Drupal.attachBehaviors($dropdown.parent()[0], Drupal.settings);
+  Drupal.facets.addDropdownChangeListener = function (context, settings) {
+    // Go to the selected option when it's clicked.
+    $(this).on('change', function () {
+      window.location.href = $(this).val();
     });
   };
 
diff --git a/src/Plugin/facets/widget/CheckboxWidget.php b/src/Plugin/facets/widget/CheckboxWidget.php
index bb92178..56ea85f 100644
--- a/src/Plugin/facets/widget/CheckboxWidget.php
+++ b/src/Plugin/facets/widget/CheckboxWidget.php
@@ -3,6 +3,8 @@
 namespace Drupal\facets\Plugin\facets\widget;
 
 use Drupal\facets\FacetInterface;
+use Drupal\Core\Render\Element\Checkbox;
+use Drupal\facets\Result\ResultInterface;
 
 /**
  * The checkbox / radios widget.
@@ -10,11 +12,31 @@ use Drupal\facets\FacetInterface;
  * @FacetsWidget(
  *   id = "checkbox",
  *   label = @Translation("List of checkboxes"),
- *   description = @Translation("A configurable widget that shows a list of checkboxes"),
+ *   description = @Translation("A configurable widget that shows a list of
+ *   checkboxes"),
  * )
  */
 class CheckboxWidget extends LinksWidget {
 
+  /**
+   * The renderer service.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
+   * Constructs a plugin object.
+   *
+   * @param array $configuration
+   *   (optional) An optional configuration to be passed to the plugin. If
+   *   empty, the plugin is initialized with its default plugin configuration.
+   */
+  public function __construct(array $configuration = []) {
+    parent::__construct($configuration);
+    $this->renderer = \Drupal::service('renderer');
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -25,4 +47,66 @@ class CheckboxWidget extends LinksWidget {
     return $build;
   }
 
+  /**
+   * Returns the text or link for an item.
+   *
+   * @param \Drupal\facets\Result\ResultInterface $result
+   *   A result item.
+   *
+   * @return array
+   *   The item as a render array.
+   * @throws \Exception
+   */
+  protected function prepareLink(ResultInterface $result) {
+    $class = get_class($this);
+    $checkboxClass = Checkbox::class;
+    $item = $this->buildResultItem($result);
+    /** @var \Drupal\Core\Render\RendererInterface $renderer */
+    $renderer = \Drupal::service('renderer');
+
+    if (!is_null($result->getUrl())) {
+      $item = [
+        '#theme' => 'input__checkbox',
+        '#title_display' => 'after',
+        '#title' => $renderer->render($item),
+        '#theme_wrappers' => ['form_element'],
+        '#value' => $result->isActive() ? TRUE : FALSE,
+        '#return_value' => $result->getUrl()->toString(),
+        '#pre_render' => [
+          [$class, 'preRenderCheckbox'],
+          [$checkboxClass, 'preRenderCheckbox'],
+        ],
+      ];
+    }
+
+    return $item;
+  }
+
+  /**
+   * Sets the #checked property of a checkbox element.
+   */
+  public static function prerenderCheckbox(&$element) {
+    $value = $element['#value'];
+    $return_value = $element['#return_value'];
+    // On form submission, the #value of an available and enabled checked
+    // checkbox is #return_value, and the #value of an available and enabled
+    // unchecked checkbox is integer 0. On not submitted forms, and for
+    // checkboxes with #access=FALSE or #disabled=TRUE, the #value is
+    // #default_value (integer 0 if #default_value is NULL). Most of the time,
+    // a string comparison of #value and #return_value is sufficient for
+    // determining the "checked" state, but a value of TRUE always means checked
+    // (even if #return_value is 'foo'), and a value of FALSE or integer 0
+    // always means unchecked (even if #return_value is '' or '0').
+    if ($value === TRUE || $value === FALSE || $value === 0) {
+      $element['#checked'] = (bool) $value;
+    }
+    else {
+      // Compare as strings, so that 15 is not considered equal to '15foo', but
+      // 1 is considered equal to '1'. This cast does not imply that either
+      // #value or #return_value is expected to be a string.
+      $element['#checked'] = ((string) $value === (string) $return_value);
+    }
+    return $element;
+  }
+
 }
diff --git a/src/Plugin/facets/widget/DropdownWidget.php b/src/Plugin/facets/widget/DropdownWidget.php
index b2e2fa9..ab65e7b 100644
--- a/src/Plugin/facets/widget/DropdownWidget.php
+++ b/src/Plugin/facets/widget/DropdownWidget.php
@@ -3,7 +3,9 @@
 namespace Drupal\facets\Plugin\facets\widget;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
 use Drupal\facets\FacetInterface;
+use Drupal\facets\Result\ResultInterface;
 use Drupal\facets\Widget\WidgetPluginBase;
 
 /**
@@ -17,24 +19,129 @@ use Drupal\facets\Widget\WidgetPluginBase;
  */
 class DropdownWidget extends WidgetPluginBase {
 
+  /**
+   * Prepares a select render element.
+   */
+  public static function preRenderSelect($element) {
+    Element::setAttributes($element, ['id', 'name', 'size']);
+    return $element;
+  }
+
   /**
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
     return [
-      'default_option_label' => 'Choose',
-    ] + parent::defaultConfiguration();
+        'default_option_label' => 'Choose',
+      ] + parent::defaultConfiguration();
   }
 
   /**
    * {@inheritdoc}
    */
   public function build(FacetInterface $facet) {
-    $build = parent::build($facet);
-    $build['#attributes']['class'][] = 'js-facets-dropdown-links';
-    $build['#attached']['drupalSettings']['facets']['dropdown_widget'][$facet->id()]['facet-default-option-label'] = $this->getConfiguration()['default_option_label'];
-    $build['#attached']['library'][] = 'facets/drupal.facets.dropdown-widget';
-    return $build;
+    $this->facet = $facet;
+    $results = $facet->getResults();
+    $options = $this->buildOptions($facet, $results);
+    $widget = $facet->getWidget();
+    $class = get_class($this);
+
+    $defaultValue = '';
+    $emptyOptionValue = $defaultValue;
+    $activeResult = $this->getActiveResult($results);
+    if($activeResult) {
+      $emptyOptionValue = $activeResult->getUrl()->toString();
+    }
+
+    $emptyOption = [
+      $emptyOptionValue => $this->getConfiguration()['default_option_label'],
+    ];
+
+    return [
+      '#type' => 'select',
+      '#facet' => $facet,
+      '#options' => $emptyOption + $options,
+      '#value' => $defaultValue,
+      '#pre_render' => [
+        [$class, 'preRenderSelect'],
+      ],
+      '#attributes' => [
+        'data-drupal-facet-id' => $facet->id(),
+        'data-drupal-facet-alias' => $facet->getUrlAlias(),
+        'class' => ['js-facets-dropdown-links', 'form-select'],
+      ],
+      '#input' => TRUE,
+      '#theme_wrappers' => ['form_element'],
+      '#context' => ['list_style' => $widget['type']],
+      '#attached' => [
+        'library' => [
+          'facets/drupal.facets.dropdown-widget',
+        ],
+      ],
+      '#cache' => [
+        'contexts' => [
+          'url.path',
+          'url.query_args',
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * Builds an array of options.
+   *
+   * @param \Drupal\facets\FacetInterface $facet
+   *   The facet we need to build.
+   * @param \Drupal\facets\Result\ResultInterface[] $results
+   *   A result item.
+   *
+   * @return array
+   *   An array of options.
+   */
+  protected function buildOptions(FacetInterface $facet, array $results) {
+    $options = [];
+    $this->appendOptions($options, $facet, $results);
+    return $options;
+  }
+
+  /**
+   * Add options to the array based on the list of results.
+   *
+   * @param array $options
+   *   The list of options for the widget.
+   * @param \Drupal\facets\FacetInterface $facet
+   *   The facet we need to build.
+   * @param \Drupal\facets\Result\ResultInterface[] $results
+   *   A list of result items.
+   */
+  protected function appendOptions(&$options, FacetInterface $facet, array $results) {
+    foreach ($results as $result) {
+      $urlString = '';
+      if(!$result->isActive()) {
+        $urlString = $result->getUrl()
+          ->toString();
+      }
+      $options[$urlString] = $this->buildResultOption($result);
+
+      $children = $result->getChildren();
+      if (empty($children)) {
+        continue;
+      }
+      $this->appendOptions($options, $facet, $children);
+    }
+  }
+
+  /**
+   * Builds a facet result item.
+   *
+   * @param \Drupal\facets\Result\ResultInterface $result
+   *   The result item.
+   *
+   * @return string
+   *   The facet result item as a render array.
+   */
+  protected function buildResultOption(ResultInterface $result) {
+    return $result->getDisplayValue();
   }
 
   /**
@@ -59,4 +166,36 @@ class DropdownWidget extends WidgetPluginBase {
     return $form;
   }
 
+  /**
+   * Get the active value of the dropdown.
+   *
+   * @param array $results
+   *  All possible results.
+   *
+   * @return \Drupal\facets\Result\ResultInterface
+   *  The result that is active.
+   */
+  protected function getActiveResult(array $results) {
+    $activeValue = FALSE;
+    foreach ($results as $result) {
+      if ($result->isActive()) {
+        return $result;
+      }
+
+      $children = $result->getChildren();
+      if(empty($children)) {
+        continue;
+      }
+
+      $activeValue = $this->getActiveResult($children);
+      if(!$activeValue) {
+        continue;
+      }
+
+      return $activeValue;
+    }
+
+    return $activeValue;
+  }
+
 }
diff --git a/templates/facets-result-item--checkbox.html.twig b/templates/facets-result-item--checkbox.html.twig
new file mode 100644
index 0000000..c250f4a
--- /dev/null
+++ b/templates/facets-result-item--checkbox.html.twig
@@ -0,0 +1,22 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a facet result item.
+ *
+ * Available variables:
+ * - value: The item value.
+ * - raw_value: The raw item value.
+ * - show_count: If this facet provides count.
+ * - count: The amount of results.
+ * - is_active: The item is active.
+ * - facet: The facet for this result item.
+ *   - id: the machine name for the facet.
+ *   - label: The facet label.
+ *
+ * @ingroup themeable
+ */
+#}
+{{ value }}
+{% if show_count %}
+  <span class="facet-item__count">({{ count }})</span>
+{% endif %}
