Documentation

Navigation bar

PublishedUpdated

A navigation bar holds destinations in a row along the bottom of the window. Each destination is a button, or a link when it has an href.

Usage

Each destination has an id, a label and an icon. active marks the current one. A badge is a count, a short text, or true for a dot with no text. badgeLabel names the badge; a dot with none is announced as "New activity".

Vanilla
import { createNavigationBar } from 'material';

const navigationBar = createNavigationBar({
  ariaLabel: 'Mail navigation',
  items: [
    {
      id: 'inbox',
      label: 'Inbox',
      icon: inboxIcon,
      badge: 8,
      active: true,
    },
    {
      id: 'favorites',
      label: 'Favorites',
      icon: heartOutlineIcon,
      badge: true,
    },
    { id: 'sent', label: 'Sent', icon: outboxIcon },
  ],
});
document.body.append(navigationBar.element);
Web Components
<m-navigation-bar value="inbox" aria-label="Mail navigation">
  <m-navigation-bar-item value="inbox" badge="8">Inbox</m-navigation-bar-item>
  <m-navigation-bar-item value="favorites" badge="">Favorites</m-navigation-bar-item>
  <m-navigation-bar-item value="sent">Sent</m-navigation-bar-item>
</m-navigation-bar>

<script type="module">
  const navigationBar = document.querySelector('m-navigation-bar');
  navigationBar.querySelector('m-navigation-bar-item[value="inbox"]').setAttribute('icon', inboxIcon);
  navigationBar.querySelector('m-navigation-bar-item[value="favorites"]').setAttribute('icon', heartOutlineIcon);
  navigationBar.querySelector('m-navigation-bar-item[value="sent"]').setAttribute('icon', outboxIcon);
</script>
React
import { useState } from 'react';
import { NavigationBar, NavigationBarItem } from 'material/react';
import { inboxIcon, heartOutlineIcon, outboxIcon } from './app';

export function Example() {
  const [value, setValue] = useState("inbox");
  return (
    <NavigationBar value={value} onChange={(event) => setValue(event.detail.value)} ariaLabel="Mail navigation">
      <NavigationBarItem value="inbox" icon={inboxIcon} badge="8">Inbox</NavigationBarItem>
      <NavigationBarItem value="favorites" icon={heartOutlineIcon} badge="">Favorites</NavigationBarItem>
      <NavigationBarItem value="sent" icon={outboxIcon}>Sent</NavigationBarItem>
    </NavigationBar>
  );
}
Vue
<script setup lang="ts">
import { ref } from 'vue';
import { MNavigationBar, MNavigationBarItem } from 'material/vue';
import { inboxIcon, heartOutlineIcon, outboxIcon } from './app';

const value = ref("inbox");
</script>

<template>
  <MNavigationBar v-model="value" aria-label="Mail navigation">
    <MNavigationBarItem value="inbox" :icon="inboxIcon" badge="8">Inbox</MNavigationBarItem>
    <MNavigationBarItem value="favorites" :icon="heartOutlineIcon" badge="">Favorites</MNavigationBarItem>
    <MNavigationBarItem value="sent" :icon="outboxIcon">Sent</MNavigationBarItem>
  </MNavigationBar>
</template>
Svelte
<script lang="ts">
  import { NavigationBar, NavigationBarItem } from 'material/svelte';
  import { inboxIcon, heartOutlineIcon, outboxIcon } from './app';

  let value = $state("inbox");
</script>

<NavigationBar bind:value ariaLabel="Mail navigation">
  <NavigationBarItem value="inbox" icon={inboxIcon} badge="8">Inbox</NavigationBarItem>
  <NavigationBarItem value="favorites" icon={heartOutlineIcon} badge="">Favorites</NavigationBarItem>
  <NavigationBarItem value="sent" icon={outboxIcon}>Sent</NavigationBarItem>
</NavigationBar>
SolidJS
import { createSignal } from 'solid-js';
import { NavigationBar, NavigationBarItem } from 'material/solid';
import { inboxIcon, heartOutlineIcon, outboxIcon } from './app';

export function Example() {
  const [value, setValue] = createSignal("inbox");
  return (
    <NavigationBar value={value()} onChange={(event) => setValue(event.detail.value)} ariaLabel="Mail navigation">
      <NavigationBarItem value="inbox" icon={inboxIcon} badge="8">Inbox</NavigationBarItem>
      <NavigationBarItem value="favorites" icon={heartOutlineIcon} badge="">Favorites</NavigationBarItem>
      <NavigationBarItem value="sent" icon={outboxIcon}>Sent</NavigationBarItem>
    </NavigationBar>
  );
}

Examples

Icon beside the label

itemLayout is vertical (the icon above the label), horizontal (the icon beside it), or auto. auto is vertical, and horizontal while the bar itself is at least 600px wide.

activeIcon is the icon shown while that destination is selected. The web component takes it as selected-icon.

Vanilla
import { createNavigationBar } from 'material';

const navigationBar = createNavigationBar({
  itemLayout: 'horizontal',
  items: [
    {
      id: 'home',
      label: 'Home',
      icon: heartOutlineIcon,
      activeIcon: heartFilledIcon,
      active: true,
    },
    { id: 'search', label: 'Search', icon: searchIcon },
  ],
});
document.body.append(navigationBar.element);
Web Components
<m-navigation-bar value="home" item-layout="horizontal">
  <m-navigation-bar-item value="home">Home</m-navigation-bar-item>
  <m-navigation-bar-item value="search">Search</m-navigation-bar-item>
</m-navigation-bar>

<script type="module">
  const navigationBar = document.querySelector('m-navigation-bar');
  navigationBar.querySelector('m-navigation-bar-item[value="home"]').setAttribute('icon', heartOutlineIcon);
  navigationBar.querySelector('m-navigation-bar-item[value="home"]').setAttribute('selected-icon', heartFilledIcon);
  navigationBar.querySelector('m-navigation-bar-item[value="search"]').setAttribute('icon', searchIcon);
</script>
React
import { useState } from 'react';
import { NavigationBar, NavigationBarItem } from 'material/react';
import { heartOutlineIcon, heartFilledIcon, searchIcon } from './app';

export function Example() {
  const [value, setValue] = useState("home");
  return (
    <NavigationBar value={value} onChange={(event) => setValue(event.detail.value)} itemLayout="horizontal">
      <NavigationBarItem value="home" icon={heartOutlineIcon} selectedIcon={heartFilledIcon}>Home</NavigationBarItem>
      <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
    </NavigationBar>
  );
}
Vue
<script setup lang="ts">
import { ref } from 'vue';
import { MNavigationBar, MNavigationBarItem } from 'material/vue';
import { heartOutlineIcon, heartFilledIcon, searchIcon } from './app';

const value = ref("home");
</script>

<template>
  <MNavigationBar v-model="value" item-layout="horizontal">
    <MNavigationBarItem value="home" :icon="heartOutlineIcon" :selected-icon="heartFilledIcon">Home</MNavigationBarItem>
    <MNavigationBarItem value="search" :icon="searchIcon">Search</MNavigationBarItem>
  </MNavigationBar>
</template>
Svelte
<script lang="ts">
  import { NavigationBar, NavigationBarItem } from 'material/svelte';
  import { heartOutlineIcon, heartFilledIcon, searchIcon } from './app';

  let value = $state("home");
</script>

<NavigationBar bind:value itemLayout="horizontal">
  <NavigationBarItem value="home" icon={heartOutlineIcon} selectedIcon={heartFilledIcon}>Home</NavigationBarItem>
  <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
</NavigationBar>
SolidJS
import { createSignal } from 'solid-js';
import { NavigationBar, NavigationBarItem } from 'material/solid';
import { heartOutlineIcon, heartFilledIcon, searchIcon } from './app';

export function Example() {
  const [value, setValue] = createSignal("home");
  return (
    <NavigationBar value={value()} onChange={(event) => setValue(event.detail.value)} itemLayout="horizontal">
      <NavigationBarItem value="home" icon={heartOutlineIcon} selectedIcon={heartFilledIcon}>Home</NavigationBarItem>
      <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
    </NavigationBar>
  );
}

Hide on scroll

hideOnScroll slides the bar out of view after the page scrolls down by 10 pixels, and back when it scrolls up. true follows the window; an object { target } follows that element's scroll instead. Focus inside the bar shows it again. hide() and show() do the same without a scroll.

Vanilla
import { createNavigationBar } from 'material';

const navigationBar = createNavigationBar({
  hideOnScroll: true,
  items: [
    { id: 'home', label: 'Home', icon: homeIcon, active: true },
    { id: 'search', label: 'Search', icon: searchIcon },
  ],
});
document.body.append(navigationBar.element);
Web Components
<m-navigation-bar value="home" hide-on-scroll>
  <m-navigation-bar-item value="home">Home</m-navigation-bar-item>
  <m-navigation-bar-item value="search">Search</m-navigation-bar-item>
</m-navigation-bar>

<script type="module">
  const navigationBar = document.querySelector('m-navigation-bar');
  navigationBar.querySelector('m-navigation-bar-item[value="home"]').setAttribute('icon', homeIcon);
  navigationBar.querySelector('m-navigation-bar-item[value="search"]').setAttribute('icon', searchIcon);
</script>
React
import { useState } from 'react';
import { NavigationBar, NavigationBarItem } from 'material/react';
import { homeIcon, searchIcon } from './app';

export function Example() {
  const [value, setValue] = useState("home");
  return (
    <NavigationBar value={value} onChange={(event) => setValue(event.detail.value)} hideOnScroll>
      <NavigationBarItem value="home" icon={homeIcon}>Home</NavigationBarItem>
      <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
    </NavigationBar>
  );
}
Vue
<script setup lang="ts">
import { ref } from 'vue';
import { MNavigationBar, MNavigationBarItem } from 'material/vue';
import { homeIcon, searchIcon } from './app';

const value = ref("home");
</script>

<template>
  <MNavigationBar v-model="value" hide-on-scroll>
    <MNavigationBarItem value="home" :icon="homeIcon">Home</MNavigationBarItem>
    <MNavigationBarItem value="search" :icon="searchIcon">Search</MNavigationBarItem>
  </MNavigationBar>
</template>
Svelte
<script lang="ts">
  import { NavigationBar, NavigationBarItem } from 'material/svelte';
  import { homeIcon, searchIcon } from './app';

  let value = $state("home");
</script>

<NavigationBar bind:value hideOnScroll>
  <NavigationBarItem value="home" icon={homeIcon}>Home</NavigationBarItem>
  <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
</NavigationBar>
SolidJS
import { createSignal } from 'solid-js';
import { NavigationBar, NavigationBarItem } from 'material/solid';
import { homeIcon, searchIcon } from './app';

export function Example() {
  const [value, setValue] = createSignal("home");
  return (
    <NavigationBar value={value()} onChange={(event) => setValue(event.detail.value)} hideOnScroll>
      <NavigationBarItem value="home" icon={homeIcon}>Home</NavigationBarItem>
      <NavigationBarItem value="search" icon={searchIcon}>Search</NavigationBarItem>
    </NavigationBar>
  );
}

A selection emits select with { id, value, index, originalEvent }. value is the destination's id, the same field the web component's change event carries. Arrow keys move between destinations along the row; Home and End move to the ends.

API

Options

Option Type Default Description
items NavigationBarItemConfig[] [] Destinations; each needs a unique id, a label and an icon
itemLayout 'auto' | 'vertical' | 'horizontal' 'auto' Icon above the label, beside it, or above until the bar is 600px wide
hideOnScroll boolean | { target?: HTMLElement | Window } off Hide on scroll down, show on scroll up; true follows the window
ariaLabel string 'Primary navigation' The landmark's accessible name
ripple boolean true false is the element's no-ripple attribute
onSelect (event: NavigationBarSelectEvent) => void select listener registered at creation

Items

Option Type Description
id string Unique among the bar's destinations
label string The text under or beside the icon
icon string SVG markup. The element takes it as icon
activeIcon string SVG markup shown while this destination is active. The element takes it as selected-icon
href string Renders the destination as a link and keeps the browser's navigation
badge string | number | boolean A count, a short text, or true for the dot
badgeLabel string The accessible name of the badge
active boolean Whether this destination starts selected
disabled boolean Whether the destination is inert

Methods

Method Returns Description
getActive() string | null The selected destination's id
setActive(id) this Selects a destination without emitting select; null clears it
getItems() NavigationBarItemConfig[] The destinations
setItems(items) this Replaces the destinations
setBadge(id, badge, label?) this Sets or clears one destination's badge
hide() this Slides the bar out of view
show() this Slides the bar back
isHidden() boolean Whether hide() or a scroll has hidden it
on(event, handler) this Listens for select or visibility
off(event, handler) this Removes that listener
destroy() void Removes the bar and its listeners

Element

<m-navigation-bar> takes value (the selected destination's id), item-layout, hide-on-scroll, no-ripple and aria-label. value is also the live property. It dispatches change with { value } and visibility with { hidden }. hide() and show() are methods.

<m-navigation-bar-item> takes value, icon, selected-icon, href, badge, badge-label and disabled. Its text is the label. An empty badge attribute is the dot.