diff --git a/config/schema/facets.facet.schema.yml b/config/schema/facets.facet.schema.yml
index 4bffcaa..238de7f 100644
--- a/config/schema/facets.facet.schema.yml
+++ b/config/schema/facets.facet.schema.yml
@@ -32,6 +32,12 @@ facets.facet.*:
     exclude:
       type: boolean
       label: 'Exclude'
+    use_hierarchy:
+      type: boolean
+      label: 'Use hierarchy'
+    expand_hierarchy:
+      type: boolean
+      label: 'Expand hierarchy'
     widget:
       type: mapping
       label: 'Facet widget'
diff --git a/src/Entity/Facet.php b/src/Entity/Facet.php
index 848713d..4b0fe8e 100644
--- a/src/Entity/Facet.php
+++ b/src/Entity/Facet.php
@@ -41,6 +41,8 @@ use Drupal\facets\FacetInterface;
  *     "facet_source_id",
  *     "widget",
  *     "query_operator",
+ *     "use_hierarchy",
+ *     "expand_hierarchy",
  *     "exclude",
  *     "only_visible_when_facet_source_is_visible",
  *     "processor_configs",
@@ -107,6 +109,20 @@ 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;
+
+  /**
+   * A boolean indicating if hierarchical items should always be expanded.
+   *
+   * @var bool
+   */
+  protected $expand_hierarchy;
+
+  /**
    * A boolean flag indicating if search should exclude selected facets.
    *
    * @var bool
@@ -392,6 +408,34 @@ class Facet extends ConfigEntityBase implements FacetInterface {
   /**
    * {@inheritdoc}
    */
+  public function setUseHierarchy($use_hierarchy) {
+    return $this->use_hierarchy = $use_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getUseHierarchy() {
+    return isset($this->use_hierarchy) ? $this->use_hierarchy : false;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setExpandHierarchy($expand_hierarchy) {
+    return $this->expand_hierarchy = $expand_hierarchy;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getExpandHierarchy() {
+    return isset($this->expand_hierarchy) ? $this->expand_hierarchy : false;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function setExclude($exclude) {
     return $this->exclude = $exclude;
   }
diff --git a/src/FacetInterface.php b/src/FacetInterface.php
index 5e9180d..9d2c48f 100644
--- a/src/FacetInterface.php
+++ b/src/FacetInterface.php
@@ -181,6 +181,44 @@ 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 plugin name for the url processor.
    *
    * @return string
diff --git a/src/FacetManager/DefaultFacetManager.php b/src/FacetManager/DefaultFacetManager.php
index c53e541..04fccbe 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 $child_ids = [];
+
+  /**
    * 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($facet->getUseHierarchy()){
+      $keyed_results = [];
+      foreach ($results as $result) {
+        $keyed_results[$result->getRawValue()] = $result;
+      }
+
+      $parent_groups = $this->getTaxonomyHierarchy(array_keys($keyed_results));
+      $keyed_results = $this->buildHierarchicalTree($keyed_results, $parent_groups);
+
+      // Remove children from primary level.
+      foreach (array_unique($this->child_ids) 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) {
@@ -366,4 +389,42 @@ class DefaultFacetManager {
     return !empty($this->facets[$facet->id()]) ? $this->facets[$facet->id()] : NULL;
   }
 
+  protected function buildHierarchicalTree($keyed_results, $parent_groups) {
+
+    foreach ($keyed_results as &$result) {
+      $current_id = $result->getRawValue();
+      $child_ids = array_keys($parent_groups, $current_id);
+      if ($child_ids) {
+        $child_keyed_results = array_filter($keyed_results, function ($k) use ($child_ids) {
+          return in_array($k, $child_ids);
+        }, ARRAY_FILTER_USE_KEY);
+        $result->setChildren($this->buildHierarchicalTree($child_keyed_results, $parent_groups));
+        $this->child_ids = array_merge($this->child_ids, $child_ids);
+      }
+    }
+
+    return $keyed_results;
+  }
+
+  /**
+   * Gets parent information for taxonomy terms.
+   *
+   * TODO: Refactor (d7 c/p) and move into a pluggable hierarchy system.
+   */
+  protected function getTaxonomyHierarchy(array $values) {
+    $result = db_select('taxonomy_term_hierarchy', 'th')
+      ->fields('th', array('tid', 'parent'))
+      ->condition('th.parent', '0', '>')
+      ->condition(db_or()
+        ->condition('th.tid', $values, 'IN')
+        ->condition('th.parent', $values, 'IN')
+      )
+      ->execute();
+
+    $parents = array();
+    foreach ($result as $record) {
+      $parents[$record->tid] = $record->parent;
+    }
+    return $parents;
+  }
 }
diff --git a/src/Form/FacetForm.php b/src/Form/FacetForm.php
index fd8b01f..eb5e4f2 100644
--- a/src/Form/FacetForm.php
+++ b/src/Form/FacetForm.php
@@ -380,6 +380,25 @@ 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>BETA: 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']['weight'] = [
       '#type' => 'number',
       '#title' => $this->t('Weight'),
@@ -581,6 +600,8 @@ 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->save();
     drupal_set_message(t('Facet %name has been updated.', ['%name' => $facet->getName()]));
diff --git a/src/Plugin/facets/query_type/SearchApiString.php b/src/Plugin/facets/query_type/SearchApiString.php
index 03504e6..fca1af3 100644
--- a/src/Plugin/facets/query_type/SearchApiString.php
+++ b/src/Plugin/facets/query_type/SearchApiString.php
@@ -54,6 +54,34 @@ class SearchApiString extends QueryTypePluginBase {
       // Add the filter to the query if there are active values.
       $active_items = $this->facet->getActiveItems();
 
+      // When the operator is OR, remove parents from the active ones if
+      // children are active. If we don't do this, sending a child and its
+      // parent will produce the same results as just sending the parent.
+      if($active_items && $this->facet->getUseHierarchy() && $this->facet->getQueryOperator() == 'or'){
+
+        // TODO: make this callback configurable, dont hardcode on terms.
+        $parents = $this->getTaxonomyHierarchy($active_items);
+
+        // Check the filters in reverse order, to avoid checking parents that
+        // will afterwards be removed anyways.
+        foreach ($active_items as $filter) {
+          // Skip this filter if it was already removed, or if it is the
+          // "missing value" filter ("!").
+          if (!in_array($filter, $active_items) || !is_numeric($filter)) {
+            continue;
+          }
+          // Go through the entire hierarchy of the value and remove all its
+          // ancestors.
+          while(!empty($parents[$filter])){
+            $active_items = array_diff( $active_items, [$parents[$filter]] ) ;
+            unset($parents[$filter]);
+            if(isset($parents[$parents[$filter]])){
+              $filter = $parents[$parents[$filter]];
+            }
+          }
+        }
+      }
+
       if (count($active_items)) {
         $filter = $query->createConditionGroup($operator, ['facet:' . $field_identifier]);
         foreach ($active_items as $value) {
@@ -86,4 +114,24 @@ class SearchApiString extends QueryTypePluginBase {
     return $this->facet;
   }
 
+  /**
+   * Temporary hardcoded function, needs to move to a HierarchyPlugin once it exists.
+   */
+  protected function getTaxonomyHierarchy(array $values) {
+    $result = db_select('taxonomy_term_hierarchy', 'th')
+      ->fields('th', array('tid', 'parent'))
+      ->condition('th.parent', '0', '>')
+      ->condition(db_or()
+        ->condition('th.tid', $values, 'IN')
+        ->condition('th.parent', $values, 'IN')
+      )
+      ->execute();
+
+    $parents = array();
+    foreach ($result as $record) {
+      $parents[$record->tid] = $record->parent;
+    }
+    return $parents;
+  }
+
 }
diff --git a/src/Result/Result.php b/src/Result/Result.php
index 6842121..555b761 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;
   }
 
   /**
diff --git a/src/Result/ResultInterface.php b/src/Result/ResultInterface.php
index d721777..0dba2ee 100644
--- a/src/Result/ResultInterface.php
+++ b/src/Result/ResultInterface.php
@@ -80,7 +80,7 @@ interface ResultInterface {
    * @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 324da68..2ade651 100644
--- a/src/Widget/WidgetPluginBase.php
+++ b/src/Widget/WidgetPluginBase.php
@@ -132,16 +132,19 @@ abstract class WidgetPluginBase extends PluginBase implements WidgetPluginInterf
    */
   protected function buildListItems(ResultInterface $result) {
     $classes = ['facet-item'];
-    if ($children = $result->getChildren()) {
+    $children = $result->getChildren();
+    if ($children && ($result->isActive() || $this->facet->getExpandHierarchy())) {
       $items = $this->prepareLink($result);
 
-      $children_markup = [];
+      $child_items = [];
       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'];
@@ -157,7 +160,6 @@ abstract class WidgetPluginBase extends PluginBase implements WidgetPluginInterf
 
     $items['#wrapper_attributes'] = ['class' => $classes];
     $items['#attributes']['data-drupal-facet-item-id'] = $this->facet->getUrlAlias() . '-' . $result->getRawValue();
-
     return $items;
   }
 
@@ -181,21 +183,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
