Drupal 8 - Taxonomy Menu with Hierarchy
I needed the same thing. Unfortunately there is nothing for it yet so I had to create something for time being. It is not pretty but it works so I don't care.

/**
 * Returns renderable array of taxonomy terms from Categories vocabulary in
 * hierarchical structure ready to be rendered as html list.
 *
 * @param int $parent
 *   The ID of the parent taxonomy term.
 *
 * @param int $max_depth
 *   The max depth up to which to look up children.
 *
 * @param string $route_name
 *   The name of the route to be used for link generation.
 *   Taxonomy term(ID) will be provided as route parameter.
 *
 * @return array
 */
function mymodule_categories_tree($parent = 0, $max_depth = NULL, $route_name = 'mymodule.category.view') {
  // Load terms
  $tree = \Drupal::entityManager()-&gt;getStorage('taxonomy_term')-&gt;loadTree('categories', $parent, $max_depth);

  // Make sure there are terms to work with.
  if (empty($tree)) {
    return [];
  }

  // Sort tree by depth so we can easily find out the deepest level
  uasort($tree, function($a, $b) {
    // Change objects to array
    return \Drupal\Component\Utility\SortArray::sortByKeyInt((array) $a, (array) $b, 'depth');
  });

  // Get the value of the deepest term
  $deepest = end($tree);
  $deepest = $deepest-&gt;depth;

  // Create a structured array
  $list = [
    $parent =&gt; [
      'items' =&gt; [],
      'depth' =&gt; -1
    ]
  ];
  foreach ($tree AS $term) {
    $list[$term-&gt;tid] = (array) $term;
  }

  // See if we're on a node page and if so open the menu
  // on the proper position.
  $node = \Drupal::request()-&gt;attributes-&gt;get('node');
  if ($node) {
    $categories = $node-&gt;get('categories')-&gt;getValue();
    // Go through each category to find out the least deep one.
    // That one will be the one we'll open.
    $open_category = $parent;
    foreach ($categories AS $target) {
      $tid = $target['target_id'];
      if ($list[$tid]['depth'] &gt; $list[$open_category]['depth']) {
        $open_category = $tid;
      }
    }
  } else {
    // See if we're on a term page and set the corresponding item
    // as active so we don't have to rely on JS.
    $term = \Drupal::request()-&gt;attributes-&gt;get('taxonomy_term');
    if ($term) {
      $open_term = $term-&gt;id();
    }
  }

  for ($i = $deepest; $i &gt;= 0; $i--) {
    foreach ($list AS $term) {
      if ($term['depth'] == $i) {
        $item = [
          '#type' =&gt; 'link',
          '#weight' =&gt; $term['weight'],
          '#title' =&gt; $term['name'],
          '#url' =&gt; Url::fromRoute($route_name, ['taxonomy_term' =&gt; $term['tid']]),
          '#options' =&gt; [
            'set_active_class' =&gt; TRUE
          ]
        ];
        // If we're on a node page and this category was chosen
        // as active, set the link's class.
        if (isset($open_category) &amp;&amp; $open_category == $term['tid']) {
          $item['#attributes']['class'][] = 'active';
        }
        // If we're on term page, set the link's class to 'active'
        // and if this item is a parent, open it.
        if (isset($open_term) &amp;&amp; $open_term == $term['tid']) {
          $item['#attributes']['class'][] = 'active';
          if (!empty($term['items'])) {
            $item['#wrapper_attributes']['class'][] = 'open';
          }
        }
        // If this item has children
        if (!empty($term['items'])) {
          $item['items'] = $term['items'];
          $item['#wrapper_attributes']['class'][] = 'parent';
          $item['#prefix'] = '&lt;span&gt;&lt;/span&gt;';
          // If any of the child items has 'active' class,
          // or is also a parent and has 'open' class
          // add the 'open' class to this wrapper too.
          foreach ($item['items'] AS $child) {
            if (
              isset($child['#attributes']['class']) &amp;&amp; in_array('active', $child['#attributes']['class'])
              || isset($child['#wrapper_attributes']['class']) &amp;&amp; in_array('open', $child['#wrapper_attributes']['class'])
            ) {
              $item['#wrapper_attributes']['class'][] = 'open';
              break;
            }
          }
        }
        foreach ($term['parents'] AS $pid) {
          $list[$pid]['items'][$term['tid']] = $item;
        }
        unset($list[$term['tid']]);
      }
    }
  }

  return [
    '#theme' =&gt; 'item_list',
    '#items' =&gt; $list[$parent]['items'],
    '#attributes' =&gt; [
      'class' =&gt; ['categories-tree']
    ],
    '#attached' =&gt; [
      'library' =&gt; [
        'mymodule/categories_tree'
      ]
    ]
  ];
}