Quick answer: A Materialize sidenav is a fixed edge menu opened by a hamburger icon, built in three steps: add the sidenav markup with an id, trigger element with data-target, initialize it with M.Sidenav.init(), and load the Materialize JS file. The two mistakes that break 90% of implementations are forgetting M.AutoInit() (or the explicit init call) and hiding the trigger behind CSS without a click handler. On desktop you can either keep the sidenav as permanent navigation or collapse it — both patterns are below, with copy-paste code.
The complete working sidenav in 3 steps
This is the full implementation — HTML, trigger and initialization. Paste it into a page that already loads Materialize CSS and JS.
<!-- Step 1: the trigger (usually inside your navbar) -->
<a href="#" data-target="slide-out" class="sidenav-trigger"><i class="material-icons">menu</i></a>
<!-- Step 2: the sidenav markup -->
<ul id="slide-out" class="sidenav">
<li><a href="#!">Dashboard</a></li>
<li><a href="#!">Profile</a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Settings</a></li>
<li><a href="#!">Logout</a></li>
</ul>
<!-- Step 3: initialization (before </body>) -->
<script>
document.addEventListener('DOMContentLoaded', function () {
var el = document.querySelectorAll('.sidenav');
M.Sidenav.init(el);
});
</script>
If you call M.AutoInit() instead, every Materialize component on the page initializes itself — convenient for learning, but explicit init is safer in real projects because you control which options each component gets. Nothing else is required: no CSS overrides, no jQuery (the old $('.button-collapse').sideNav() tutorials were written for 0.97.x and fail on 1.0.0).
Sidenav options that matter
| Option | Values | Effect |
|---|---|---|
| edge | ‘left’ (default) or ‘right’ | Which screen side the drawer slides from |
| draggable | true (default) / false | Whether swipe from the edge opens it on touch devices |
| inDuration | milliseconds, default 250 | Open animation speed |
| outDuration | milliseconds, default 200 | Close animation speed |
| preventScrolling | false (default) / true | Lock body scroll while the sidenav is open |
M.Sidenav.init(el, {
edge: 'right',
draggable: true,
preventScrolling: true
});
Setting edge: 'right' is the whole implementation for a right-side drawer — there is no separate right-sidenav component; the right-side sidenav guide covers the two-line version and its gotchas. preventScrolling: true is the option most people wish they had found earlier: without it, the page behind the open drawer keeps scrolling on phones.
Making the sidenav your main navigation
Two patterns cover almost every real site: the mobile drawer pattern (sidenav only below the breakpoint, horizontal navbar above it) and the persistent sidenav pattern (always visible on desktop as the site’s primary menu). Materialize supports both with the same component — persistence is a CSS media query, not a JS option:
/* Persistent sidenav: pin it open on desktop */
@media (min-width: 993px) {
.sidenav {
transform: translateX(0%) !important;
box-shadow: none;
}
.sidenav-trigger { display: none; } /* hide hamburger */
}
That single rule is how you run a sidenav as the main navigation on desktop while keeping the slide-in drawer on mobile — the approach taken by the sidenav as main navigation and width customization posts, which handle the sidebar width and content offset details. For accordion-style sub-menus inside the drawer, the accordion submenu pattern nests collapsible lists.
When the sidenav does not open: the four culprits
- JS file missing or loaded before the DOM. The sidenav is JavaScript — no
materialize.min.js, no drawer. Wrap init inDOMContentLoaded. - No init call. Markup alone does nothing on 1.0.0.
M.Sidenav.init()orM.AutoInit()is mandatory. - data-target mismatch. The trigger’s
data-targetmust equal theul idexactly, character for character. - z-index buried. Sidenav uses z-index 500; hero sliders and modals can outrank it. Check the trigger exists in the DOM before blaming CSS — hidden
display:nonetriggers never fire clicks.
Also confirm your page is on 1.0.0, not an old 0.97.x file: initialization syntax changed completely between versions, and mixing a 1.0.0 CSS with 0.97 JS produces exactly the silent failure above. The version rules are covered in the Materialize CSS tutorial that opens this series.
Building a real app shell and want your markup reviewed line by line? Ampersand Academy teaches Materialize and front-end layout one-to-one, using your own project as the curriculum.
Frequently asked questions
Why is my Materialize sidenav not working?
Four usual causes: the Materialize JavaScript file is missing, no M.Sidenav.init() call ran, the trigger data-target does not match the ul id, or a newer 1.0.0 CSS is paired with old 0.97.x jQuery-era initialization code.
How do I open a Materialize sidenav from the right side?
Pass one option at initialization: M.Sidenav.init(el, { edge: ‘right’ }). No other change is needed — edge only flips which screen side the drawer animates from.
How do I make the sidenav always visible on desktop?
Add a media query for min-width 993px that sets transform: translateX(0) on the sidenav and hides the hamburger trigger. The component stays the same; CSS pins it open above the breakpoint.
Do I still need jQuery for Materialize sidenav?
No. Materialize 1.0.0 dropped jQuery entirely — it ships its own vanilla-JS initialization through M.Sidenav.init() and M.AutoInit(). jQuery code from old tutorials simply errors.
How do I close the sidenav when clicking a link?
Call the instance method sidenav.close() from the link click handler, or use href with the instance API after init. For hash links, closing before navigating keeps the transition smooth.

