diff --git a/config/schema/facets.facet.schema.yml b/config/schema/facets.facet.schema.yml
index 4bffcaa..d5a5095 100644
--- a/config/schema/facets.facet.schema.yml
+++ b/config/schema/facets.facet.schema.yml
@@ -32,6 +32,15 @@ facets.facet.*:
     exclude:
       type: boolean
       label: 'Exclude'
+    use_hierarchy:
+      type: boolean
+      label: 'Use hierarchy'
+    expand_hierarchy:
+      type: boolean
+      label: 'Expand hierarchy'
+    enable_parent_when_child_gets_disabled:
+      type: boolean
+      label: 'Enable parent when child gets disabled'
     widget:
       type: mapping
       label: 'Facet widget'
diff --git a/core_search_facets/src/Plugin/facets/query_type/CoreNodeSearchDate.php b/core_search_facets/src/Plugin/facets/query_type/CoreNodeSearchDate.php
index 7a83fb4..9312f34 100644
--- a/core_search_facets/src/Plugin/facets/query_type/CoreNodeSearchDate.php
+++ b/core_search_facets/src/Plugin/facets/query_type/CoreNodeSearchDate.php
@@ -114,7 +114,8 @@ class CoreNodeSearchDate extends QueryTypePluginBase {
           $result->setActiveState(TRUE);
           // Sets the children for the current parent..
           if ($parent) {
-            $parent->setChildren($result);
+            $children = array_merge($parent->getChildren(), [$result]);
+            $parent->setChildren($children);
           }
           else {
             $parent = $parent_facet_results[] = $result;
@@ -180,7 +181,8 @@ class CoreNodeSearchDate extends QueryTypePluginBase {
       $parent = end($parent_facet_results);
       if ($parent instanceof ResultInterface) {
         foreach ($facet_results as $result) {
-          $parent->setChildren($result);
+          $children = array_merge($parent->getChildren(), [$result]);
+          $parent->setChildren($children);
           $this->facet->setResults($parent_facet_results);
         }
       }
diff --git a/css/hierarchical.css b/css/hierarchical.css
new file mode 100644
index 0000000..e3b845e
--- /dev/null
+++ b/css/hierarchical.css
@@ -0,0 +1,3 @@
+.block-facets ul ul li {
+    margin-left: 10px;
+}
diff --git a/facets.libraries.yml b/facets.libraries.yml
index 643be6f..8e08f96 100644
--- a/facets.libraries.yml
+++ b/facets.libraries.yml
@@ -30,6 +30,12 @@ drupal.facets.checkbox-widget:
     - core/drupal
     - core/jquery.once
 
+drupal.facets.hierarchical:
+  version: VERSION
+  css:
+    theme:
+      css/hierarchical.css: {}
+
 drupal.facets.dropdown-widget:
   version: VERSION
   js:
diff --git a/facets.services.yml b/facets.services.yml
index 9a3fdb6..fcd8d70 100644
--- a/facets.services.yml
+++ b/facets.services.yml
@@ -14,6 +14,9 @@ services:
   plugin.manager.facets.url_processor:
     class: Drupal\facets\UrlProcessor\UrlProcessorPluginManager
     parent: default_plugin_manager
+  plugin.manager.facets.hierarchy:
+    class: Drupal\facets\Hierarchy\HierarchyPluginManager
+    parent: default_plugin_manager
   facets.manager:
     class: Drupal\facets\FacetManager\DefaultFacetManager
     arguments:
diff --git a/js/checkbox-widget.js b/js/checkbox-widget.js
index 7506685..7ca1934 100644
--- a/js/checkbox-widget.js
+++ b/js/checkbox-widget.js
@@ -21,6 +21,8 @@
     // 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);
   };
 
   /**
diff --git a/src/Annotation/FacetsHierarchy.php b/src/Annotation/FacetsHierarchy.php
new file mode 100644
index 0000000..d3ec151
--- /dev/null
+++ b/src/Annotation/FacetsHierarchy.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\facets\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a Facets Hierarchy annotation.
+ *
+ * @see \Drupal\facets\Hierarchy\HierarchyPluginManager
+ * @see plugin_api
+ *
+ * @ingroup plugin_api
+ *
+ * @Annotation
+ */
+class FacetsHierarchy extends Plugin {
+
+  /**
+   * The Hierarchy plugin id.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The human-readable name of the Hierarchy plugin.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $label;
+
+  /**
+   * The Hierarchy description.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $description;
+
+}
diff --git a/src/Entity/Facet.php b/src/Entity/Facet.php
index db3f13a..de05aa0 100644
--- a/src/Entity/Facet.php
+++ b/src/Entity/Facet.php
@@ -41,6 +41,9 @@ use Drupal\facets\FacetInterface;
  *     "facet_source_id",
  *     "widget",
  *     "query_operator",
+ *     "use_hierarchy",
+ *     "expand_hierarchy",
+ *     "enable_parent_when_child_gets_disabled",
  *     "exclude",
  *     "only_visible_when_facet_source_is_visible",
  *     "processor_configs",
@@ -100,6 +103,20 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   protected $widgetInstance;
 
   /**
+   * The hierarchy definition.
+   *
+   * @var array
+   */
+  protected $hierarchy;
+
+  /**
+   * The hierarchy instance.
+   *
+   * @var \Drupal\facets\Hierarchy\HierarchyPluginBase
+   */
+  protected $hierarchy_processor;
+
+  /**
    * The operator to hand over to the query, currently AND | OR.
    *
    * @var string
@@ -107,6 +124,27 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   protected $query_operator;
 
   /**
+   * A boolean indicating if items should be rendered in hierarchical structure.
+   *
+   * @var bool
+   */
+  protected $use_hierarchy = FALSE;
+
+  /**
+   * A boolean indicating if hierarchical items should always be expanded.
+   *
+   * @var bool
+   */
+  protected $expand_hierarchy = FALSE;
+
+  /**
+   * Wether or not parents should be enabled when a child gets disabled.
+   *
+   * @var bool
+   */
+  protected $enable_parent_when_child_gets_disabled = TRUE;
+
+  /**
    * A boolean flag indicating if search should exclude selected facets.
    *
    * @var bool
@@ -261,6 +299,18 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   }
 
   /**
+   * Returns the hierarchy plugin manager.
+   *
+   * @return \Drupal\facets\Hierarchy\HierarchyPluginManager
+   *   The hierarchy plugin manager.
+   */
+  public function getHierarchyManager() {
+    $container = \Drupal::getContainer();
+
+    return $this->widget_plugin_manager ?: $container->get('plugin.manager.facets.hierarchy');
+  }
+
+  /**
    * {@inheritdoc}
    */
   protected function urlRouteParameters($rel) {
@@ -319,6 +369,45 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function setHierarchy($id, array $configuration = NULL) {
+    if ($configuration === NULL) {
+      $instance = $this->getHierarchyManager()->createInstance($id);
+      // Get the default configuration for this plugin.
+      $configuration = $instance->getConfiguration();
+    }
+    $this->hierarchy = ['type' => $id, 'config' => $configuration];
+
+    // Unset the hierarchy instance, if exists.
+    unset($this->hierarchy_instance);
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getHierarchy() {
+    // TODO: do not hardcode on taxonomy, make this configurable (or better,
+    // autoselected depending field type).
+    return ['type' => 'taxonomy', 'config' => []];
+    // return $this->hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getHierarchyInstance() {
+    if (!isset($this->hierarchy_instance)) {
+      $definition = $this->getHierarchy();
+      $this->hierarchy_instance = $this->getHierarchyManager()
+        ->createInstance($definition['type'], (array) $definition['config']);
+    }
+    return $this->hierarchy_instance;
+  }
+
+  /**
    * Retrieves all processors supported by this facet.
    *
    * @return \Drupal\facets\Processor\ProcessorInterface[]
@@ -392,6 +481,48 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   /**
    * {@inheritdoc}
    */
+  public function setUseHierarchy($use_hierarchy) {
+    return $this->use_hierarchy = $use_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getUseHierarchy() {
+    return $this->use_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setExpandHierarchy($expand_hierarchy) {
+    return $this->expand_hierarchy = $expand_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getExpandHierarchy() {
+    return $this->expand_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setEnableParentWhenChildGetsDisabled($enable_parent_when_child_gets_disabled) {
+    return $this->enable_parent_when_child_gets_disabled = $enable_parent_when_child_gets_disabled;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEnableParentWhenChildGetsDisabled() {
+    return $this->enable_parent_when_child_gets_disabled;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function setExclude($exclude) {
     return $this->exclude = $exclude;
   }
diff --git a/src/FacetInterface.php b/src/FacetInterface.php
index 135ec41..2a41103 100644
--- a/src/FacetInterface.php
+++ b/src/FacetInterface.php
@@ -41,6 +41,37 @@ interface FacetInterface extends ConfigEntityInterface {
   public function getWidgetInstance();
 
   /**
+   * Sets the facet hierarchy definition.
+   *
+   * @param string $id
+   *   The hierarchy plugin id.
+   * @param array $configuration
+   *   (optional) The facet hierarchy plugin configuration. When empty, the
+   *   default plugin configuration will be used.
+   *
+   * @return $this
+   */
+  public function setHierarchy($id, array $configuration = NULL);
+
+  /**
+   * Returns the facet hierarchy definition.
+   *
+   * @return array
+   *   An associative array with the following structure:
+   *   - id: The hierarchy plugin id as a string.
+   *   - config: The widget configuration as an array.
+   */
+  public function getHierarchy();
+
+  /**
+   * Returns the facet hierarchy instance.
+   *
+   * @return \Drupal\facets\Hierarchy\HierarchyPluginBase
+   *   The plugin instance
+   */
+  public function getHierarchyInstance();
+
+  /**
    * Returns field identifier.
    *
    * @return string
@@ -181,6 +212,63 @@ interface FacetInterface extends ConfigEntityInterface {
   public function getExclude();
 
   /**
+   * Returns the value of the use_hierarchy boolean.
+   *
+   * This will return true when the results in the facet should be rendered in
+   * a hierarchical structure.
+   *
+   * @return bool
+   *   A boolean flag indicating if results should be rendered using hierarchy.
+   */
+  public function getUseHierarchy();
+
+  /**
+   * Sets the use_hierarchy.
+   *
+   * @param bool $use_hierarchy
+   *   A boolean flag indicating if results should be rendered using hierarchy.
+   */
+  public function setUseHierarchy($use_hierarchy);
+
+  /**
+   * Returns the value of the expand_hierarchy boolean.
+   *
+   * This will return true when the results in the facet should be expanded in
+   * a hierarchical structure, regardless of active state.
+   *
+   * @return bool
+   *   Wether or not results should always be expanded using hierarchy.
+   */
+  public function getExpandHierarchy();
+
+  /**
+   * Sets the expand_hierarchy.
+   *
+   * @param bool $expand_hierarchy
+   *   Wether or not results should always be expanded using hierarchy.
+   */
+  public function setExpandHierarchy($expand_hierarchy);
+
+  /**
+   * Returns the value of the enable_parent_when_child_gets_disabled boolean.
+   *
+   * This will return true when the parent item in the facet should be enabled
+   * in an hierarchical structure, when a child facet item gets disabled.
+   *
+   * @return bool
+   *   Wether or not parents should be enabled when a child gets disabled.
+   */
+  public function getEnableParentWhenChildGetsDisabled();
+
+  /**
+   * Sets the enable_parent_when_child_gets_disabled.
+   *
+   * @param bool $enable_parent_when_child_gets_disabled
+   *   Wether or not parents should be enabled when a child gets disabled.
+   */
+  public function setEnableParentWhenChildGetsDisabled($enable_parent_when_child_gets_disabled);
+
+  /**
    * Returns the plugin name for the url processor.
    *
    * @return string
diff --git a/src/FacetManager/DefaultFacetManager.php b/src/FacetManager/DefaultFacetManager.php
index c59d19a..b279f17 100644
--- a/src/FacetManager/DefaultFacetManager.php
+++ b/src/FacetManager/DefaultFacetManager.php
@@ -66,6 +66,11 @@ class DefaultFacetManager {
   protected $facets = [];
 
   /**
+   * An array of all entity ids in the active resultset which are a child.
+   */
+  protected $childIds = [];
+
+  /**
    * An array flagging which facet source' facets have been processed.
    *
    * This variable acts as a semaphore that ensures facet data is processed
@@ -292,6 +297,24 @@ class DefaultFacetManager {
       $results = $processor->build($facet, $results);
     }
 
+    // Handle hierarchy.
+    if ($results && $facet->getUseHierarchy()) {
+      $keyed_results = [];
+      foreach ($results as $result) {
+        $keyed_results[$result->getRawValue()] = $result;
+      }
+
+      $parent_groups = $facet->getHierarchyInstance()->getChildIds(array_keys($keyed_results));
+      $keyed_results = $this->buildHierarchicalTree($keyed_results, $parent_groups);
+
+      // Remove children from primary level.
+      foreach (array_unique($this->childIds) as $child_id) {
+        unset($keyed_results[$child_id]);
+      }
+
+      $results = array_values($keyed_results);
+    }
+
     // Trigger sort stage.
     $active_sort_processors = [];
     foreach ($facet->getProcessorsByStage(ProcessorInterface::STAGE_SORT) as $processor) {
@@ -377,4 +400,37 @@ class DefaultFacetManager {
     return !empty($this->facets[$facet->id()]) ? $this->facets[$facet->id()] : NULL;
   }
 
+  /**
+   * Builds an hierarchical structure for results.
+   *
+   * When given an array of results and an array which defines the hierarchical
+   * structure, this will build the results structure and set all childs.
+   *
+   * @param \Drupal\facets\Result\ResultInterface[] $keyed_results
+   *   An array of results keyed by id.
+   * @param array $parent_groups
+   *   An array of 'child id arrays' keyed by their parent id.
+   *
+   * @return \Drupal\facets\Result\ResultInterface[]
+   *   An array of results structured hierarchicaly.
+   */
+  protected function buildHierarchicalTree($keyed_results, $parent_groups) {
+    foreach ($keyed_results as &$result) {
+      $current_id = $result->getRawValue();
+      if (isset($parent_groups[$current_id]) && $parent_groups[$current_id]) {
+        $child_ids = $parent_groups[$current_id];
+        $child_keyed_results = [];
+        foreach($child_ids as $child_id){
+          if(isset($keyed_results[$child_id])){
+            $child_keyed_results[$child_id] = $keyed_results[$child_id];
+          }
+        }
+        $result->setChildren($this->buildHierarchicalTree($child_keyed_results, $parent_groups));
+        $this->childIds = array_merge($this->childIds, $child_ids);
+      }
+    }
+
+    return $keyed_results;
+  }
+
 }
diff --git a/src/Form/FacetForm.php b/src/Form/FacetForm.php
index fd8b01f..3fb5999 100644
--- a/src/Form/FacetForm.php
+++ b/src/Form/FacetForm.php
@@ -380,6 +380,37 @@ class FacetForm extends EntityForm {
       '#default_value' => $facet->getExclude(),
     ];
 
+    $form['facet_settings']['use_hierarchy'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Use hierarchy'),
+      '#description' => $this->t('Renders the items using hierarchy. Requires the hierarchy processor configured in search api for this field. If disabled all items will be flatten.') . '<br/><strong>At this moment only hierarchical taxonomy terms are supported.</strong>',
+      '#default_value' => $facet->getUseHierarchy(),
+    ];
+
+    $form['facet_settings']['expand_hierarchy'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Always expand hierarchy'),
+      '#description' => $this->t('Render entire tree, regardless of whether the parents are active or not.'),
+      '#default_value' => $facet->getExpandHierarchy(),
+      '#states' => array(
+        'visible' => array(
+          ':input[name="facet_settings[use_hierarchy]"]' => array('checked' => TRUE),
+        ),
+      ),
+    ];
+
+    $form['facet_settings']['enable_parent_when_child_gets_disabled'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Enable parent when child gets disabled'),
+      '#description' => $this->t('Uncheck this if you want to allow de-activating an entire hierarchical trail by clicking an active child.'),
+      '#default_value' => $facet->getExpandHierarchy(),
+      '#states' => array(
+        'visible' => array(
+          ':input[name="facet_settings[use_hierarchy]"]' => array('checked' => TRUE),
+        ),
+      ),
+    ];
+
     $form['facet_settings']['weight'] = [
       '#type' => 'number',
       '#title' => $this->t('Weight'),
@@ -581,6 +612,9 @@ class FacetForm extends EntityForm {
     $facet->setQueryOperator($form_state->getValue(['facet_settings', 'query_operator']));
 
     $facet->setExclude($form_state->getValue(['facet_settings', 'exclude']));
+    $facet->setUseHierarchy($form_state->getValue(['facet_settings', 'use_hierarchy']));
+    $facet->setExpandHierarchy($form_state->getValue(['facet_settings', 'expand_hierarchy']));
+    $facet->setEnableParentWhenChildGetsDisabled($form_state->getValue(['facet_settings', 'enable_parent_when_child_gets_disabled']));
 
     $facet->save();
     drupal_set_message(t('Facet %name has been updated.', ['%name' => $facet->getName()]));
diff --git a/src/Hierarchy/HierarchyInterface.php b/src/Hierarchy/HierarchyInterface.php
new file mode 100644
index 0000000..a30f96b
--- /dev/null
+++ b/src/Hierarchy/HierarchyInterface.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\facets\Hierarchy;
+
+/**
+ * Interface HierarchyInterface.
+ */
+interface HierarchyInterface {
+
+  /**
+   * Retrieve all parent ids for one specific id.
+   *
+   * @param string $id
+   *   An entity id.
+   *
+   * @return array
+   *   An array of all parent ids.
+   */
+  public function getParentIds($id);
+
+  /**
+   * Retrieve all children and nested children for one specific id.
+   *
+   * @param string $id
+   *   An entity id.
+   *
+   * @return array
+   *   An array of all child ids.
+   */
+  public function getNestedChildIds($id);
+
+  /**
+   * Retrieve the direct children for an array of ids.
+   *
+   * @param array $ids
+   *   An array of ids.
+   *
+   * @return array
+   *   Given parent ids as key, value is an array of child ids.
+   */
+  public function getChildIds($ids);
+
+}
diff --git a/src/Hierarchy/HierarchyPluginBase.php b/src/Hierarchy/HierarchyPluginBase.php
new file mode 100644
index 0000000..96dc4dc
--- /dev/null
+++ b/src/Hierarchy/HierarchyPluginBase.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\facets\Hierarchy;
+
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\facets\Processor\ProcessorPluginBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * A base class for plugins that implements most of the boilerplate.
+ */
+abstract class HierarchyPluginBase extends ProcessorPluginBase implements HierarchyInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    /** @var \Symfony\Component\HttpFoundation\Request $request */
+    $request = $container->get('request_stack')->getMasterRequest();
+    return new static($configuration, $plugin_id, $plugin_definition, $request);
+  }
+
+}
diff --git a/src/Hierarchy/HierarchyPluginManager.php b/src/Hierarchy/HierarchyPluginManager.php
new file mode 100644
index 0000000..7df981d
--- /dev/null
+++ b/src/Hierarchy/HierarchyPluginManager.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\facets\Hierarchy;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Manages Hierarchy plugins.
+ *
+ * @see \Drupal\facets\Annotation\FacetsProcessor
+ * @see \Drupal\facets\Processor\ProcessorInterface
+ * @see \Drupal\facets\Processor\ProcessorPluginBase
+ * @see plugin_api
+ */
+class HierarchyPluginManager extends DefaultPluginManager {
+
+  use StringTranslationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/facets/hierarchy', $namespaces, $module_handler, 'Drupal\facets\Hierarchy\HierarchyInterface', 'Drupal\facets\Annotation\FacetsHierarchy');
+    $this->setCacheBackend($cache_backend, 'facets_hierarchy');
+  }
+
+}
diff --git a/src/Plugin/facets/hierarchy/Taxonomy.php b/src/Plugin/facets/hierarchy/Taxonomy.php
new file mode 100644
index 0000000..5f0514b
--- /dev/null
+++ b/src/Plugin/facets/hierarchy/Taxonomy.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\facets\Plugin\facets\hierarchy;
+
+use Drupal\facets\Hierarchy\HierarchyPluginBase;
+
+/**
+ * Taxonomy hierarchy.
+ *
+ * @FacetsHierarchy(
+ *   id = "taxonomy",
+ *   label = @Translation("Taxonomy hierarchy"),
+ *   description = @Translation("Hierarchy structure provided by the taxonomy module.")
+ * )
+ */
+class Taxonomy extends HierarchyPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getParentIds($id) {
+    $current_tid = $id;
+    while ($parent = $this->taxonomyGetParent($current_tid)) {
+      $current_tid = $parent;
+      $parents[$id][] = $parent;
+    }
+    return isset($parents[$id]) ? $parents[$id] : [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getNestedChildIds($id) {
+    $children = &drupal_static(__FUNCTION__, []);
+    if (!isset($children[$id])) {
+      // TODO: refactor to swap out deprecated db_select.
+      $query = db_select('taxonomy_term_hierarchy', 'h');
+      $query->addField('h', 'tid');
+      $query->condition('h.parent', $id);
+      $queried_children = $query->execute()->fetchCol();
+      $subchilds = [];
+      foreach ($queried_children as $child) {
+        $subchilds = array_merge($subchilds, $this->getNestedChildIds($child));
+      }
+      $children[$id] = array_merge($queried_children, $subchilds);
+    }
+    return isset($children[$id]) ? $children[$id] : [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getChildIds($ids) {
+    // TODO: refactor to swap out deprecated db_select.
+    // TODO: also check if this query does not too much, plain d7 c/p here.
+    $result = db_select('taxonomy_term_hierarchy', 'th')
+      ->fields('th', array('tid', 'parent'))
+      ->condition('th.parent', '0', '>')
+      ->condition(db_or()
+        ->condition('th.tid', $ids, 'IN')
+        ->condition('th.parent', $ids, 'IN')
+      )
+      ->execute();
+
+    $parents = array();
+    foreach ($result as $record) {
+      $parents[$record->parent][] = $record->tid;
+    }
+    return $parents;
+  }
+
+  /**
+   * Returns the parent tid for a given tid, or false if no parent exists.
+   *
+   * @param int $tid
+   *   A taxonomy term id.
+   *
+   * @return int|false
+   *   Returns FALSE if no parent is found, else parent tid.
+   */
+  protected function taxonomyGetParent($tid) {
+    // TODO: refactor to swap out deprecated db_select.
+    $parent = &drupal_static(__FUNCTION__, []);
+
+    if (!isset($parent[$tid])) {
+      $query = db_select('taxonomy_term_hierarchy', 'h');
+      $query->addField('h', 'parent');
+      $query->condition('h.tid', $tid);
+      $parent[$tid] = $query->execute()->fetchField();
+    }
+    return isset($parent[$tid]) ? $parent[$tid] : FALSE;
+  }
+
+}
diff --git a/src/Plugin/facets/url_processor/QueryString.php b/src/Plugin/facets/url_processor/QueryString.php
index 2de000f..7de537a 100644
--- a/src/Plugin/facets/url_processor/QueryString.php
+++ b/src/Plugin/facets/url_processor/QueryString.php
@@ -93,10 +93,28 @@ class QueryString extends UrlProcessorPluginBase {
             unset($filter_params[$key]);
           }
         }
+        if ($facet->getEnableParentWhenChildGetsDisabled() && $facet->getUseHierarchy()) {
+          // Enable parent id again if exists.
+          $parent_ids = $facet->getHierarchyInstance()->getParentIds($result->getRawValue());
+          if ($parent_ids[0]) {
+            $filter_params[] = $this->urlAlias . self::SEPARATOR . $parent_ids[0];
+          }
+        }
       }
       // If the value is not active, add the filter string.
       else {
         $filter_params[] = $filter_string;
+
+        if ($facet->getUseHierarchy()) {
+          // If hierarchy is active, unset parent trail and every child when
+          // building the enable-link to ensure those are not enabled anymore.
+          $parent_ids = $facet->getHierarchyInstance()->getParentIds($result->getRawValue());
+          $child_ids = $facet->getHierarchyInstance()->getNestedChildIds($result->getRawValue());
+          $parents_and_child_ids = array_merge($parent_ids, $child_ids);
+          foreach ($parents_and_child_ids as $id) {
+            $filter_params = array_diff($filter_params, [$this->urlAlias . self::SEPARATOR . $id]);
+          }
+        }
         // Exclude currently active results from the filter params if we are in
         // the show_only_one_result mode.
         if ($facet->getShowOnlyOneResult()) {
diff --git a/src/Plugin/facets/widget/LinksWidget.php b/src/Plugin/facets/widget/LinksWidget.php
index fe8cba0..5e16f6b 100644
--- a/src/Plugin/facets/widget/LinksWidget.php
+++ b/src/Plugin/facets/widget/LinksWidget.php
@@ -34,6 +34,9 @@ class LinksWidget extends WidgetPluginBase {
       $build['#attached']['library'][] = 'facets/soft-limit';
       $build['#attached']['drupalSettings']['facets']['softLimit'][$facet->id()] = $soft_limit;
     }
+    if ($facet->getUseHierarchy()) {
+      $build['#attached']['library'][] = 'facets/drupal.facets.hierarchical';
+    }
     return $build;
   }
 
diff --git a/src/Result/Result.php b/src/Result/Result.php
index 6842121..578e2ea 100644
--- a/src/Result/Result.php
+++ b/src/Result/Result.php
@@ -129,8 +129,8 @@ class Result implements ResultInterface {
   /**
    * {@inheritdoc}
    */
-  public function setChildren(ResultInterface $children) {
-    $this->children[] = $children;
+  public function setChildren(array $children) {
+    $this->children = $children;
   }
 
   /**
@@ -140,4 +140,19 @@ class Result implements ResultInterface {
     return $this->children;
   }
 
+  /**
+   * Returns true if the value has active children(selected).
+   *
+   * @return bool $active
+   *   A boolean indicating the active state of children.
+   */
+  public function hasActiveChildren() {
+    foreach ($this->getChildren() as $child) {
+      if ($child->isActive() || $child->hasActiveChildren()) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
 }
diff --git a/src/Result/ResultInterface.php b/src/Result/ResultInterface.php
index 2dcebc6..0323404 100644
--- a/src/Result/ResultInterface.php
+++ b/src/Result/ResultInterface.php
@@ -66,6 +66,14 @@ interface ResultInterface {
   public function isActive();
 
   /**
+   * Returns true if the value has active children(selected).
+   *
+   * @return bool $active
+   *   A boolean indicating the active state of children.
+   */
+  public function hasActiveChildren();
+
+  /**
    * Overrides the display value of a result.
    *
    * @param string $display_value
@@ -76,10 +84,10 @@ interface ResultInterface {
   /**
    * Sets children results.
    *
-   * @param \Drupal\facets\Result\ResultInterface $children
+   * @param \Drupal\facets\Result\ResultInterface[] $children
    *   The children to be added.
    */
-  public function setChildren(ResultInterface $children);
+  public function setChildren(array $children);
 
   /**
    * Returns children results.
diff --git a/src/Widget/WidgetPluginBase.php b/src/Widget/WidgetPluginBase.php
index f5ada7d..c20b1a2 100644
--- a/src/Widget/WidgetPluginBase.php
+++ b/src/Widget/WidgetPluginBase.php
@@ -132,32 +132,40 @@ abstract class WidgetPluginBase extends PluginBase implements WidgetPluginInterf
    */
   protected function buildListItems(ResultInterface $result) {
     $classes = ['facet-item'];
-    if ($children = $result->getChildren()) {
-      $items = $this->prepareLink($result);
+    $items = $this->prepareLink($result);
 
-      $children_markup = [];
+    $children = $result->getChildren();
+    // Check if we need to expand this result.
+    if ($children && ($this->facet->getExpandHierarchy() || $result->isActive() || $result->hasActiveChildren())) {
+
+      $child_items = [];
+      $classes[] = 'facet-item--expanded';
       foreach ($children as $child) {
-        $children_markup[] = $this->buildChild($child);
+        $child_items[] = $this->buildListItems($child);
       }
 
-      $classes[] = 'expanded';
-      $items['children'] = [$children_markup];
+      $items['children'] = [
+        '#theme' => 'item_list',
+        '#items' => $child_items,
+      ];
 
-      if ($result->isActive()) {
-        $items['#attributes'] = ['class' => 'active-trail'];
+      if ($result->hasActiveChildren()) {
+        $classes[] = 'facet-item--active-trail';
       }
+
     }
     else {
-      $items = $this->prepareLink($result);
-
-      if ($result->isActive()) {
-        $items['#attributes'] = ['class' => 'is-active'];
+      if ($children) {
+        $classes[] = 'facet-item--collapsed';
       }
     }
 
+    if ($result->isActive()) {
+      $items['#attributes'] = ['class' => 'is-active'];
+    }
+
     $items['#wrapper_attributes'] = ['class' => $classes];
     $items['#attributes']['data-drupal-facet-item-id'] = $this->facet->getUrlAlias() . '-' . $result->getRawValue();
-
     return $items;
   }
 
@@ -181,21 +189,6 @@ abstract class WidgetPluginBase extends PluginBase implements WidgetPluginInterf
   }
 
   /**
-   * Builds a result item as a render array.
-   *
-   * @param \Drupal\facets\Result\ResultInterface $child
-   *   A result item.
-   *
-   * @return array
-   *   The result item as render array.
-   */
-  protected function buildChild(ResultInterface $child) {
-    $item = $this->prepareLink($child);
-    $item['#wrapper_attributes'] = ['class' => ['leaf']];
-    return $item;
-  }
-
-  /**
    * Builds a facet result item.
    *
    * @param \Drupal\facets\Result\ResultInterface $result
diff --git a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
index 174e3e1..64f8764 100644
--- a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
+++ b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
@@ -179,7 +179,7 @@ class LinksWidgetTest extends UnitTestCase {
 
     $child = new Result('snake', 'Snake', 5);
     $original_results[1]->setActiveState(TRUE);
-    $original_results[1]->setChildren($child);
+    $original_results[1]->setChildren([$child]);
 
     $facet = new Facet([], 'facets_facet');
     $facet->setResults($original_results);
@@ -201,8 +201,8 @@ class LinksWidgetTest extends UnitTestCase {
       $this->assertEquals($value, $output['#items'][$index]['#title']);
       $this->assertEquals('link', $output['#items'][$index]['#type']);
       if ($index === 1) {
-        $this->assertEquals('active-trail', $output['#items'][$index]['#attributes']['class']);
-        $this->assertEquals(['facet-item', 'expanded'], $output['#items'][$index]['#wrapper_attributes']['class']);
+        $this->assertEquals('is-active', $output['#items'][$index]['#attributes']['class']);
+        $this->assertEquals(['facet-item', 'facet-item--expanded'], $output['#items'][$index]['#wrapper_attributes']['class']);
       }
       else {
         $this->assertEquals(['facet-item'], $output['#items'][$index]['#wrapper_attributes']['class']);
