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.

Planning preview

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})`;
});

Workspace navigation toolbar

The same workspace navigation groups arranged horizontally in Materialize’s Toolbar. Scroll the toolbar to reach every group on narrow screens.

Out.
Prod.
Studio
Admin

Production workspace

Home

Your production workspace: quick access to the tools you use every day.

One workspace, every department.

Choose a tool from the navigation to preview its destination.

Home selected.

Markup — Crazy buttons and navigation groups
<div class="workspace-nav-preview" data-layout="toolbar">
<div class="workspace-demo-navigation toolbar" aria-label="Production navigation" role="group">
  <div class="workspace-demo-group toolbar-group" role="group" aria-label="Workspace">
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="home" label="Home" data-redirect-name="Home" color-primary="gold" color-secondary="#211b00" aria-current="page"></crazy-button>
    <crazy-button type="floating" size="large" shape="box" depth="flat" icon-text="schedule" label="Timelog" data-redirect-name="Timelog" color-secondary="var(--md-sys-color-primary)"></crazy-button>
  </div>
  <div class="workspace-demo-group toolbar-group" role="group" aria-label="Out.">
    <span>Out.</span>
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="social_distance" label="Outsource Turnover" data-redirect-name="OutsourceTurnover" color-primary="#4fc3f7" color-secondary="#052e3c"></crazy-button>
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="microwave" label="Brief Outsource" data-redirect-name="OutsourceBrief" color-primary="#26a69a" color-secondary="#002e29"></crazy-button>
  </div>
  <div class="workspace-demo-group toolbar-group" role="group" aria-label="Prod.">
    <span>Prod.</span>
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="schedule" label="Timelog Summary" data-redirect-name="TimelogSummary" color-primary="#ab47bc" color-secondary="#fff"></crazy-button>
  </div>
  <div class="workspace-demo-group toolbar-group" role="group" aria-label="Studio">
    <span>Studio</span>
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="stadium" label="Studio Resource" data-redirect-name="StudioResource" color-primary="#ec407a" color-secondary="#fff"></crazy-button>
    <crazy-button type="floating" size="large" shape="box" depth="1" icon-text="view_timeline" label="Crew Planning" data-redirect-name="Planning" color-primary="#ef6c00" color-secondary="#fff"></crazy-button>
  </div>
  <div class="workspace-demo-group toolbar-group" role="group" aria-label="Admin">
    <span>Admin</span>
    <crazy-button type="floating" size="large" shape="box" depth="flat" icon-text="settings" label="Settings" data-redirect-name="Settings" color-secondary="var(--md-sys-color-on-surface)"></crazy-button>
  </div>
</div>
  <div class="workspace-demo-content">
    <p class="workspace-demo-eyebrow">Production workspace</p>
    <h4 data-workspace-title>Home</h4>
    <p class="workspace-demo-description" data-workspace-description>Your production workspace: quick access to the tools you use every day.</p>
    <div class="workspace-demo-detail"><strong>One workspace, every department.</strong><p>Choose a tool from the navigation to preview its destination.</p></div>
    <p data-crazy-button-status role="status">Home selected.</p>
  </div>
</div>

The section colors follow the reference; the surrounding surfaces follow the environment theme. data-redirect-name retains the original route identifiers. These examples update the preview; connect buttonaction to your application router for real navigation. Preview layout styles are shown below.

Preview layout CSS
// Documentation preview layout; all controls are kmaterialize CrazyButton instances.
.workspace-nav-preview {
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: 20px;
  overflow: hidden;
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  margin: 24px 0;
  .workspace-demo-navigation {
    background: var(--md-sys-color-surface-container, var(--md-sys-color-surface-variant));
    box-shadow: none;
    color: var(--md-sys-color-on-surface-variant);
    height: auto;
    line-height: normal;
  }
  .workspace-demo-group { display: flex; align-items: center; gap: 12px; }
  .workspace-demo-group > span { font-size: 11px; font-weight: 600; letter-spacing: .04em; }
  crazy-button { flex-shrink: 0; }
  crazy-button[aria-current='page'] { outline: 2px solid var(--md-sys-color-primary); outline-offset: 4px; border-radius: 16px; }
  .workspace-demo-content { min-width: 0; padding: clamp(16px, 4vw, 32px); }
  .workspace-demo-eyebrow { margin: 0 0 12px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--md-sys-color-on-surface-variant); }
  h4 { font-size: clamp(22px, 3vw, 32px); margin: 0 0 12px; }
  .workspace-demo-description { font-size: 14px; line-height: 1.6; }
  .workspace-demo-detail { margin-top: 24px; padding: 16px; border-radius: 12px; background: var(--md-sys-color-surface-variant); font-size: 13px; }
  &[data-layout='rail'] {
    display: grid;
    grid-template-columns: 88px minmax(0, 1fr);
    .workspace-demo-navigation { display: flex; flex-direction: column; align-items: center; gap: 24px; padding: 20px 0; }
    .workspace-demo-group { flex-direction: column; }
    .workspace-demo-content { border-left: 1px solid var(--md-sys-color-outline-variant); }
  }
  &[data-layout='toolbar'] {
    .toolbar { margin: 0; border-radius: 0; padding: 16px; gap: 24px; }
    .workspace-demo-group > span { writing-mode: vertical-rl; transform: rotate(180deg); }
  }
}

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:

volume_down

volume_up

<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.

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.