Region specific menu templates in Twig and Drupal 10

Why I Needed Region-Specific Menu Templates

Drupal’s core theming layer only recognises two menu templates out-of-the-box:

menu.html.twig                 ← global fallback
menu--{menu_name}.html.twig     ← e.g. menu--top.html.twig

When I placed the same Top menu block twice—once in header_top and once in mobile—both instances rendered with the same markup. I wanted totally different HTML for each region, not just different block wrappers.

Step 1. Pass the Region Down to the Menu Template

Create (or edit) copernicus.theme in your theme folder and add a hook that injects the block’s region into the inner menu render array:

use Drupal\block\Entity\Block;

/**
 * Implements hook_preprocess_block().
 * Adds the block’s region as an attribute on the child menu render array.
 */
function MYTHEME_preprocess_block(array &$variables) {
  if (!isset($variables['elements']['#id'])) {
    return;                       // Skip anonymous blocks.
  }

  $region = Block::load($variables['elements']['#id'])->getRegion();
  $variables['content']['#attributes']['region'] = $region;
}

Step 2. Add a Theme-Hook Suggestion per Region

/**
 * Implements hook_theme_suggestions_menu_alter().
 */
function MYTHEME_theme_suggestions_menu_alter(array &$suggestions, array $variables) {
  // Work only on the “top” menu.
  if (($variables['menu_name'] ?? '') !== 'top') {
    return;
  }

  // Pick up the region we injected in preprocess_block().
  if (isset($variables['attributes']['region'])) {
    // Convert anything non-alphanumeric to an underscore,
    // matching Drupal’s internal sanitiser.
    $region = preg_replace('/[^A-Za-z0-9_]+/', '_', $variables['attributes']['region']);

    // Append the new suggestion (last = highest priority).
    $suggestions[] = "menu__top__{$region}";
  }
}

After a cache rebuild (drush cr or the UI), Drupal will look for templates such as menu--top--header-first.html.twig or menu--top--mobile.html.twig before it falls back to the generic files.

Step 3. Create the Region-Specific Twig Files

themes/custom/copernicus/templates/navigation/
  ├── menu--top--header-first.html.twig
  └── menu--top--mobile.html.twig

Add your custom markup inside each:

{# menu--top--header-first.html.twig #}
<nav class="top-nav desktop">
  {{ block.content }}
</nav>
{# menu--top--mobile.html.twig #}
<nav class="top-nav mobile" data-mobile-toggle>
  {{ block.content }}
</nav>

Debugging Checklist (When Drupal Ignores Your File)

  • Filename & dashes – must exactly match the suggestion; header-first in the filename becomes header_first in PHP hooks.
  • Location – anywhere under templates/ in the active theme.
  • Permissions – readable by the web-server user (644 is fine).
  • Cache – drush cr after every new or renamed Twig file.

 

Saved you some valuable time?

Buy me a drink 🍺 to keep me motivated to create free content like this!