Toolbar
Materialize is a modern responsive CSS framework based on Material Design by Google.
Zoom controls
Use − and + to change zoom in 10% steps, from 50% to 200%. Click the percentage button to reset to 100%.
The zoom group can also sit inside another toolbar, alongside a toolbar-group. Nested zoom groups have no outer margins and keep their buttons vertically centered. The parent toolbar uses justify-content: space-between, so the action group sits at the opposite end.
This example uses the page theme colors for the toolbar, zoom pill and buttons. The download and refresh buttons illustrate the neighboring group layout.
Design → Review → Delivery
Zoom: 100%.
<div class="toolbar my-0">
<div id="planning-zoom-controls" class="toolbar toolbar-zoom" role="group" aria-label="Planning zoom">
<crazy-button id="planning-zoom-out" class="toolbar-zoom-out" label="Zoom Out" size="small" shape="round" depth="flat" icon-text="remove" variant="tonal"></crazy-button>
<crazy-button id="planning-zoom-in" class="toolbar-zoom-in" label="Zoom In" size="small" shape="round" depth="flat" icon-text="add" variant="tonal"></crazy-button>
<crazy-button id="planning-zoom-reset" type="extended" class="toolbar-zoom-reset" label="100%" size="small" shape="round" depth="flat" aria-label="Zoom 100 percent. Reset to 100 percent"></crazy-button>
</div>
<div class="toolbar-group" role="group" aria-label="Planning actions">
<crazy-button label="Download" size="small" shape="round" depth="flat" icon-text="download" variant="tonal" color-secondary="var(--md-sys-color-primary)"></crazy-button>
<crazy-button label="Refresh" size="small" shape="round" depth="flat" icon-text="refresh" variant="tonal" color-secondary="var(--md-sys-color-primary)"></crazy-button>
</div>
</div>let zoom = 100;
const controls = document.querySelector('#planning-zoom-controls');
controls.addEventListener('buttonaction', (event) => {
const id = event.target.id;
if (id === 'planning-zoom-out') zoom = Math.max(50, zoom - 10);
else if (id === 'planning-zoom-in') zoom = Math.min(200, zoom + 10);
else if (id === 'planning-zoom-reset') zoom = 100;
else return;
document.querySelector('#planning-zoom-reset').setAttribute('label', `${zoom}%`);
document.querySelector('#planning-zoom-reset').setAttribute('aria-label', `Zoom ${zoom} percent. Reset to 100 percent`);
document.querySelector('#planning-zoom-out').toggleAttribute('disabled', zoom === 50);
document.querySelector('#planning-zoom-in').toggleAttribute('disabled', zoom === 200);
// Replace with your chart's zoom API, for example chart.setZoom(zoom / 100).
document.querySelector('#planning-zoom-preview').style.transform = `scale(${zoom / 100})`;
});A rounded "pill" action bar for grouping controls above the content they act on - buttons, a segmented "track" control (e.g. Today/Previous/Next), and an expandable search field. It's a plain flex row in normal page flow, not fixed or sticky.
<div class="toolbar">
<div class="toolbar-group">
<div class="toolbar-track">
<div class="toolbar-track-indicator"></div>
<button class="toolbar-track-item is-active">Today</button>
<button class="toolbar-track-item">Previous</button>
<button class="toolbar-track-item">Next</button>
</div>
</div>
<div class="toolbar-group">
<div class="toolbar-search">
<button class="toolbar-search-toggle"><i class="material-icons">search</i></button>
<input class="toolbar-search-input" placeholder="Search...">
</div>
<button class="btn-floating btn-small"><i class="material-icons">refresh</i></button>
</div>
</div>Groups
toolbar-group clusters related controls (buttons, a track, a search field, ...) with a small gap between them, and a bigger gap
between groups themselves - the toolbar lays groups out with justify-content: space-between.
A regular btn fits into a group just as well as a btn-floating:
<div class="toolbar">
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">add</i></a>
<a class="btn-floating btn-small"><i class="material-icons">remove</i></a>
<a class="btn filled btn-small">Reset</a>
<a class="btn-floating btn-small"><i class="material-icons">crop_free</i></a>
</div>
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">download</i></a>
<a class="btn-floating btn-small"><i class="material-icons">refresh</i></a>
</div>
</div>Track (segmented control)
A pill-shaped segmented control with a sliding highlight behind whichever toolbar-track-item is
is-active. Click an item below - the Toolbar component slides the
toolbar-track-indicator to match.
<div class="toolbar-track">
<div class="toolbar-track-indicator"></div>
<button class="toolbar-track-item">Week</button>
<button class="toolbar-track-item is-active">Month</button>
<button class="toolbar-track-item">6 Month</button>
<button class="toolbar-track-item">Year</button>
</div>
Add toolbar-track-bare for a track with no background/border of its own - just for spacing a group of items that don't need
the pill-within-a-pill look:
<div class="toolbar-track toolbar-track-bare">
<div class="toolbar-track-indicator"></div>
<button class="toolbar-track-item is-active">List</button>
<button class="toolbar-track-item">Grid</button>
</div>Slider
toolbar-slider wraps a plain range-field in the same pill container
as toolbar-track - it's not just cosmetic: the range's native track line is the same color as the toolbar's own background,
so without a container to contrast against it's invisible. The container also vertically centers any label text/icons placed next to it.
With custom labels on each side (e.g. a zoom level):
<div class="toolbar-slider">
<span>-</span>
<p class="range-field">
<input type="range" min="70" max="150" value="100">
</p>
<span>+</span>
</div>With icons instead of text, or no label at all:
<div class="toolbar-slider">
<i class="material-icons">volume_down</i>
<p class="range-field"><input type="range"></p>
<i class="material-icons">volume_up</i>
</div>
<!-- no label at all -->
<div class="toolbar-slider">
<p class="range-field"><input type="range"></p>
</div>See Range for the full component documentation.
Dropdown
A real Dropdown instance, triggered from a button inside a
toolbar-group - same dropdown-trigger/dropdown-content
markup as everywhere else, auto-initialized like any other dropdown on the page.
<div class="toolbar-group">
<a class="dropdown-trigger btn-floating btn-small" href="#" data-target="toolbar-dropdown-sort"><i class="material-icons">sort</i></a>
</div>
<ul id="toolbar-dropdown-sort" class="dropdown-content">
<li><a href="#!">Name</a></li>
<li><a href="#!">Date</a></li>
<li><a href="#!">Priority</a></li>
</ul>Same M.Dropdown.init()/getInstance() API as on the Dropdown page - nothing toolbar-specific about it.
Expandable Search
Starts as just an icon button and expands into a text input on focus (or once it has a value) - click the icon below. Press
Escape to clear and collapse it again.
<div class="toolbar-search">
<button class="toolbar-search-toggle"><i class="material-icons">search</i></button>
<input class="toolbar-search-input" placeholder="Search...">
</div>Overflow
When there are more groups/buttons than fit on one line, .toolbar defaults to a plain horizontal scroll (no visible scrollbar,
still fully scrollable by trackpad/touch/shift+wheel) rather than squeezing everything to fit. Shrink your browser window below to see it kick in on this example
with 14 buttons:
<div class="toolbar">
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">home</i></a>
<a class="btn-floating btn-small"><i class="material-icons">search</i></a>
<!-- ...12 more... -->
</div>
</div>
Add toolbar-wrap to drop to a new line instead of scrolling, if that suits the content better - same 14 buttons, same container
width:
<div class="toolbar toolbar-wrap">
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">home</i></a>
<!-- ... -->
</div>
</div>Separator
A thin vertical line between groups, for when the usual gap isn't explicit enough. Drop toolbar-separator in as a sibling
between two toolbar-group elements:
<div class="toolbar">
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">format_bold</i></a>
<a class="btn-floating btn-small"><i class="material-icons">format_italic</i></a>
</div>
<div class="toolbar-separator"></div>
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">format_align_left</i></a>
<!-- ... -->
</div>
</div>Freeze a group
toolbar-freeze-left/toolbar-freeze-right keeps a group pinned at that edge while the rest
of an overflowing, scrolling toolbar moves underneath it - handy for a button (refresh, close, ...) that should always stay reachable no
matter how far the user has scrolled. Scroll the row below - the icon on the right never moves:
<div class="toolbar">
<div class="toolbar-group">
<a class="btn-floating btn-small"><i class="material-icons">home</i></a>
<!-- ...more buttons, enough to overflow... -->
</div>
<div class="toolbar-group toolbar-freeze-right">
<a class="btn-floating btn-small"><i class="material-icons">refresh</i></a>
</div>
</div>Same idea on the left with toolbar-freeze-left instead.
Initialization
Auto-initializes on every .toolbar element via Auto Init, or explicitly:
var elems = document.querySelectorAll('.toolbar');
var instances = M.Toolbar.init(elems, options);Or with jQuery:
var instance = M.Toolbar.getInstance(elem);Methods
| Method | Description |
|---|---|
updateIndicators() |
Re-measures and repositions every track's sliding indicator. Call it after changing which toolbar-track-item is active from your own code (rather than by a user click), or after anything else that could have changed the toolbar's layout/width. |
destroy() |
Removes the instance's event listeners. |