Site icon Ampersand Tutorials

Materialize CSS Dropdown Menu: Complete Guide (2026)

Quick answer: A Materialize dropdown is a floating menu attached to a trigger element. Build it in three steps: create a ul with class dropdown-content and a unique id, add a trigger with class="dropdown-trigger" and a matching data-target, then initialize it with M.Dropdown.init(). The two features people miss most are hover: true for mouse-open menus and constrainWidth: false when the menu should be wider than its trigger. The most common failure is a data-target that does not match the ul id.

The complete dropdown in 3 steps

This is the full implementation on Materialize 1.0.0 — trigger, menu, and initialization.

<!-- Step 1: the trigger -->
<a class="dropdown-trigger btn" href="#!" data-target="user-menu">
  Actions <i class="material-icons right">arrow_drop_down</i>
</a>

<!-- Step 2: the dropdown menu -->
<ul id="user-menu" class="dropdown-content">
  <li><a href="#!">Profile</a></li>
  <li><a href="#!">Settings</a></li>
  <li class="divider"></li>
  <li><a href="#!">Sign out</a></li>
</ul>

<!-- Step 3: initialization (before </body>) -->
<script>
  document.addEventListener('DOMContentLoaded', function () {
    var elems = document.querySelectorAll('.dropdown-trigger');
    M.Dropdown.init(elems);
  });
</script>

Notice the menu is a plain list, not a nested component. That is what makes the dropdown flexible: you can fill the ul with links, dividers, or even an avatar row without changing the initialization. If you call M.AutoInit() instead, every dropdown on the page initializes itself with default options — convenient for learning, less predictable in production.

Dropdown options that matter

OptionDefaultWhat it does
alignment‘left’Which side of the trigger the menu aligns to
constrainWidthtrueWhen true, the menu matches the trigger width
coverTriggertrueMenu covers the trigger or opens below it
closeOnClicktrueCloses the menu after a menu item is clicked
hoverfalseOpens on hover instead of click
inDuration150Open animation, in milliseconds
outDuration250Close animation, in milliseconds
onOpenStartnullCallback fired before the menu opens
M.Dropdown.init(document.querySelectorAll('.dropdown-trigger'), {
  alignment: 'right',
  constrainWidth: false,
  coverTrigger: false,
  hover: true
});

For a top navigation bar this exact configuration is the common one: right-aligned, free-width and hover-opened so the menu feels like a classic desktop menu. Setting constrainWidth: false is essential when menu labels are longer than the trigger — otherwise Materialize clips them to the trigger width.

Opening a dropdown from JavaScript

When the trigger is built dynamically or you need to open the menu programmatically, use the instance API instead of a click:

var instance = M.Dropdown.getInstance(document.querySelector('#user-menu'));
instance.open();
instance.close();
instance.recalculateDimensions(); // call after resizing or changing the trigger

The recalculateDimensions() call is the fix for a menu that points to the wrong place after the page layout shifts — for example when a navbar grows or a responsive breakpoint fires. Navbar placement has its own details in the navbar guide, and dropdowns that must sit inside a slide-out drawer are covered by the sidenav guide.

Nested menus and submenus

Materialize has no built-in submenu component, so a multi-level menu tabs a second ul into the first on hover. The full CSS and markup for that pattern — including the delay that stops the submenu flickering shut — is in the nested dropdown guide. For a mobile accordion, the accordion submenu approach nests collapsible lists instead.

When the dropdown does not open: four culprits

Menus that mix text fields or buttons with dropdown items are worth reviewing against the forms guide and the Materialize CSS tutorial, which cover the input and component basics these menus rely on.

Building a navigation system for a real product and want feedback on the markup? Ampersand Academy reviews front-end layouts one-to-one, using your own project as the curriculum.

Frequently asked questions

Why is my Materialize dropdown not working?

The most common causes are a data-target that does not match the ul id, a missing M.Dropdown.init() call, or an ancestor with overflow hidden that clips the menu.

How do I make a Materialize dropdown open on hover?

Pass hover set to true at initialization: M.Dropdown.init(elems, { hover: true }). The menu then opens on mouse enter instead of waiting for a click.

How do I make a Materialize dropdown wider than its trigger?

Set constrainWidth to false. By default the menu is forced to the trigger width, which clips longer labels; disabling it lets the menu size to its own content.

Does Materialize support nested or submenu dropdowns?

Not out of the box. A submenu is a second ul positioned by custom CSS on hover, which the nested dropdown guide walks through with the delay needed to stop flicker.

How do I open a Materialize dropdown programmatically?

Get the instance with M.Dropdown.getInstance(elem) and call open() or close(). Call recalculateDimensions() after the trigger moves so the menu stays aligned.

Exit mobile version