I have a complete example for twitter bootstrap, I use:
Note: this code is incomplete, maybe broken with beta update, but it's an example/introduction.
function nature_menu_link(array $variables) {
$element = $variables['element'];
$sub_menu = '';
if ($element['#below']) {
// Prevent dropdown functions from being added to management menu so it
// does not affect the navbar module.
if (($element['#original_link']['menu_name'] == 'management') && (module_exists('navbar'))) {
$sub_menu = \Drupal::service('renderer')->renderRoot($element['#below']);
}
elseif ((!empty($element['#original_link']['depth'])) && ($element['#original_link']['depth'] == 1)) {
// Add our own wrapper.
unset($element['#below']['#theme_wrappers']);
$sub_menu = '<ul class="dropdown-menu">' . \Drupal::service('renderer')->renderRoot($element['#below']) . '</ul>';
// Generate as standard dropdown.
$element['#title'] .= ' <span class="caret"></span>';
$element['#attributes']['class'][] = 'dropdown';
$element['#localized_options']['html'] = TRUE;
// Set dropdown trigger element to # to prevent inadvertant page loading
// when a submenu link is clicked.
$element['#localized_options']['attributes']['data-target'] = '#';
$element['#localized_options']['attributes']['class'][] = 'dropdown-toggle';
$element['#localized_options']['attributes']['data-toggle'] = 'dropdown';
}
}
// On primary navigation menu, class 'active' is not set on active menu item.
// @see https://drupal.org/node/1896674
if (($element['#href'] == '<front>' && drupal_is_front_page()) && (empty($element['#localized_options']['language']))) {
$element['#attributes']['class'][] = 'active';
}
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
return '<li' . new Attribute($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}
After I have my view nammed "menu--main.html.twig" :
{# https://api.drupal.org/api/drupal/core!modules!system!templates!menu.html.twig/8
menu_name: The machine name of the menu.
items: A nested list of menu items. Each menu item contains:
attributes: HTML attributes for the menu item.
below: The menu item child items.
title: The menu link title.
url: The menu link url, instance of \Drupal\Core\Url
localized_options: Menu link localized options.
#}
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ front_page }}">Site Name : {{ site_name }}</a>
</div>
<div class="collapse navbar-collapse">
{# All menu and submenu items #}
<ul class="nav navbar-nav">
{% for item in items %}
{# Menu with submenu #}
{% if item.below %}
<li class="dropdown">
<a tabindex="0" data-toggle="dropdown">{{ item.title }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{# Menu -> Submenu #}
{% for item in item.below %}
{% include "@nature/snippet/menu-infinite-child.html.twig" with { 'item': item } %}
{% endfor %}
</ul>
</li>
{# Menu without submenu #}
{% else %}
{# Menu - Link #}
<li><a tabindex="0" href="" {{ item.attributes }}>{{ item.title }}</a></li>
{# Menu - Separator #}
{% if loop.last == false %}<li class="divider"></li>{% endif %}
{% endif %}
{% endfor %}
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a tabindex="0" data-toggle="dropdown">Dropdown 3<span class="caret"></span></a>
<!-- role="menu": fix moved by arrows (Bootstrap dropdown) -->
<ul class="dropdown-menu" role="menu">
<li><a tabindex="0">Action</a></li>
<li><a tabindex="0">Another action</a></li>
<li><a tabindex="0">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="0">Separated link</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
This view call "menu-infinite-child.html.twig" for unlimited infinite child (submenu) :
{# Submenu -> Submenu #}
{% if item.below %}
<li class="dropdown-submenu">
<a tabindex="0" data-toggle="dropdown">{{ item.title }}</a>
<ul class="dropdown-menu">
{% for item in item.below %}
{% include "@nature/snippet/menu-infinite-child.html.twig" with { 'item': item } %}
{% endfor %}
</ul>
</li>
{# Submenu without Submenu #}
{% else %}
<li><a tabindex="0">{{ item.title }}</a></li>
{% endif %}
Note: I use this configuration with bootstrap-submenu http://vsn4ik.github.io/bootstrap-submenu (MIT license).