Skip to Main Content
Mosaic
  • Use in projects
  • Home
  • Browse components
    • Colors
    • Themes
    • Icons
    • Grid
    • Links
    • Typography
    • Spacing Utilities
    • SVG
    • Accordions
    • Alerts
    • Badges
    • Breadcrumb
    • Buttons
    • Copy to clipboard
    • Cards
    • Featured Container
    • Filter Bar
    • Lists
    • Loading Spinners
    • Modals
    • Pagination
    • Progress Bars
    • Progress Indicator
    • Site Banner
    • Tables
    • Tabs
    • Toast
    • Toggle Switches
    • Well
    • Wizard
    • Events
    • File Browser
    • File Upload
    • Footer
    • Header
    • Hero
    • Post Item
    • Profile
    • Sidebar Navigation
    • Splash
    • Stack
    • Form Instructions
    • Form Layout
    • Form Validation
    • Form Output
    • Checkboxes
    • Labels
    • Radio Buttons
    • Search Input
    • Select
    • Text Inputs

Header

Definition

The Header navigation component is a basic navigation bar that is used to help users navigate websites and applications. It is typically fixed to the top of the page but not to the top of the viewport, meaning that if a user scrolls down the navigation scrolls with the rest of the content.

The Header consists of:

  • A global navigation bar, required
    • A login button/dropdown, optional
  • A local navigation bar with logo, required
  • A search bar, optional

Purpose

The purpose of the header navigation component is to provide users with an easy and intuitive way to navigate websites and applications. It allows users to quickly access different pages or sections of the site, as well as switch between different products or services if applicable.

Structure and Function

The current structure affords the ability to navigate to internal pages and other products (other URLs) that might be child products of the parent organization.

Use the primary colored top bar for links that go to ICPSR pages. Use the white bar below for links within your current application or product.

The navigation component will switch to a "drawer" that is opened with a navbar-toggler on smaller screens.

Styling

The navigation component's color will be based on the theme color for the product implementing it.

Dropdowns

For large websites, use dropdown menus to help users preview lower-level content. If lower-level sections are closely related and users will need to quickly jump between them, consider using the navigation sidebar instead of — or in addition to — a dropdown.

  • Share data
    • Option 1
    • Option 2
    • Option 3

Accessibility Considerations

Semantic markup conveys the menu structure to users. Menus coded semantically can easily adapt to different situations, such as small screen displays, screen magnification, and other assistive technology.

Identify the menu using the HTML5 <nav> element to allow users access to the menu directly.

Use an ordered list when the sequence of the menu items is important. Use an unordered list when the menu items are not in a specific order.

Include skip navigation links to allow users with screen readers to bypass long navigation lists. Make sure you include an id at the beginning of your main content and that it matches the skipnav link. See the code snippet at the end of this page for an example.

Labels

Label menus to make them easier to find and understand. Labels should be short but descriptive, to allow users to distinguish between multiple menus on a web page. Make sure the following labels are present in your navigation component:

<nav class="header" aria-label="Main Navigation"> 

<button class="btn btn-close btn-close-white" aria-label="Close"></button>

Overall, the header navigation component is an essential part of any website or application, providing users with an intuitive and accessible way to navigate the site or app. By following these guidelines, you can ensure that your navigation component is effective, efficient, and accessible to all users.

Sample code

Scroll the container below to explore the full header navigation example.

See a full page example of the header navigation

Skip to Main Content
Data Lumos
  • About
  • Help
  • ICPSR Membership
    • Overview
    • Member list
    • How to join
    • Official rep tools
    • Promoting ICPSR
    • News & publications
    • Biennial meeting
  • Find data
  • Share data
    • Option 1
    • Option 2
    • Option 3
  • Summer program
    • Lorem
    • Lorem ipsum
    • Lorem ipsum dolor sit amet
  • Teaching & learning
    • Lorem
    • Lorem ipsum
    • Lorem ipsum dolor sit amet
  • Data management
    • Lorem
    • Lorem ipsum
    • Lorem ipsum dolor sit amet
  • Login

<header>
  <div id="skip"><a href="#skipto">Skip to Main Content</a></div>
  <nav class="header full">
    <a class="department-logo" href="/static/docs/">
      <picture>
        <source
          media="(max-width: 1400px)"
          srcset="https://test.datalumos.org/datalumos/resources/commons/images/datalumos/datalumos-logo.png"
        />
        <source
          media="(min-width: 1401px)"
          srcset="https://test.datalumos.org/datalumos/resources/commons/images/datalumos/datalumos-logo.png"
        />
        <img
          src="https://test.datalumos.org/datalumos/resources/commons/images/datalumos/datalumos-logo.png"
          alt="Data Lumos"
        />
      </picture>
    </a>
    <button
      class="btn btn-icon offscreen-toggler"
      popovertarget="offscreen-nav"
      popovertargetaction="show">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
        <path
          d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"
        ></path></svg
      >
    </button>
    <div class="offscreen" id="offscreen-nav">
      <button
        class="btn btn-close btn-close-white"
        aria-label="Close"
        popovertarget="offscreen-nav"
        popovertargetaction="hide"></button>
      <div class="global-nav">
        <ul class="nav-list">
          <li class="nav-item">
            <a class="nav-link" href="#" aria-current="false">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#" aria-current="false">Help</a>
          </li>
          <li class="nav-item">
            <details class="nav-item">
              <summary class="nav-link">ICPSR Membership</summary>
              <ul>
                <li><a class="dropdown-item" href="#">Overview</a></li>
                <li><a class="dropdown-item" href="#">Member list</a></li>
                <li><a class="dropdown-item" href="#">How to join</a></li>
                <li>
                  <a class="dropdown-item" href="#">Official rep tools</a>
                </li>
                <li><a class="dropdown-item" href="#">Promoting ICPSR</a></li>
                <li>
                  <a class="dropdown-item" href="#">News &amp; publications</a>
                </li>
                <li><a class="dropdown-item" href="#">Biennial meeting</a></li>
              </ul>
            </details>
          </li>
        </ul>
      </div>
      <div class="local-nav">
        <ul class="nav-list">
          <li class="nav-item">
            <a class="nav-link" href="#" aria-current="false">Find data</a>
          </li>
          <li class="nav-item">
            <details class="nav-item">
              <summary class="nav-link">Share data</summary>
              <ul>
                <li><a class="dropdown-item" href="#">Option 1</a></li>
                <li><a class="dropdown-item" href="#">Option 2</a></li>
                <li><a class="dropdown-item" href="#">Option 3</a></li>
              </ul>
            </details>
          </li>
          <li class="nav-item">
            <details class="nav-item">
              <summary class="nav-link">Summer program</summary>
              <ul>
                <li><a class="dropdown-item" href="#">Lorem</a></li>
                <li><a class="dropdown-item" href="#">Lorem ipsum</a></li>
                <li>
                  <a class="dropdown-item" href="#"
                    >Lorem ipsum dolor sit amet</a
                  >
                </li>
              </ul>
            </details>
          </li>
          <li class="nav-item">
            <details class="nav-item">
              <summary class="nav-link">Teaching &amp; learning</summary>
              <ul>
                <li><a class="dropdown-item" href="#">Lorem</a></li>
                <li><a class="dropdown-item" href="#">Lorem ipsum</a></li>
                <li>
                  <a class="dropdown-item" href="#"
                    >Lorem ipsum dolor sit amet</a
                  >
                </li>
              </ul>
            </details>
          </li>
          <li class="nav-item">
            <details class="nav-item">
              <summary class="nav-link">Data management</summary>
              <ul>
                <li><a class="dropdown-item" href="#">Lorem</a></li>
                <li><a class="dropdown-item" href="#">Lorem ipsum</a></li>
                <li>
                  <a class="dropdown-item" href="#"
                    >Lorem ipsum dolor sit amet</a
                  >
                </li>
              </ul>
            </details>
          </li>
        </ul>
      </div>
      <div class="login-nav">
        <ul class="nav-list">
          <li class="nav-item">
            <a class="btn nav-link" href="#" aria-current="false">
              <svg
                class="icon-inline"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 448 512">
                <path
                  d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"
                ></path></svg
              >
              Login
            </a>
          </li>
        </ul>
      </div>
    </div>
    <div class="nav-search">
      <form action="">
        <search class="search-input" role="search">
          <select
            class="form-select"
            id="search-options"
            name="search options"
            aria-label="Search options">
            <option value="data" selected=""> Search for data </option>
            <option value="content" selected=""> Search for content </option>
          </select>
          <div class="input-group">
            <input
              class="form-control"
              type="text"
              aria-label="Enter keywords and submit to search ICPSR for data"
              aria-describedby="nav-search"
              placeholder="Search by ID, PI name, etc"
            />
            <button class="btn btn-primary" id="nav-search" type="submit">
              <i class="fas fa-search"></i>
              <span class="visually-hidden">Search</span>
            </button>
          </div>
        </search>
      </form>
    </div>
  </nav>
</header>

The mobile menu display is built using the Popover API. The navigation is designed to automatically switch from desktop style to the mobile style depending on the horizontal space available. This means that sites with more top level navigation items (and/or longer labels) will switch to the mobile menu style at a wider viewport width than a site wih fewer top level navigation items.

The javascript code below is required to implement the automatic switching between the mobile and desktop navigation styles.

<script is:inline>
  // close menus automatically
  const detailsElements = Array.from(document.querySelectorAll("details"));
  document.addEventListener("click", (e) => {
    if (
      !detailsElements.some(
        (f) => e.target instanceof Node && f.contains(e.target)
      )
    ) {
      detailsElements.forEach((f) => f.removeAttribute("open"));
    }
  });
  detailsElements.forEach((deet) => {
    deet.addEventListener("toggle", toggleOpenOneOnly);
  });
  function toggleOpenOneOnly() {
    if (this.open) {
      detailsElements.forEach((deet) => {
        if (deet !== this && deet.open) deet.open = false;
      });
    }
  }

  // close all menus if focus moves to outside the navigation
  const main = document.querySelector("main");
  const login = document.querySelector(".login-nav");
  main?.addEventListener("focusin", (event) => {
    detailsElements.forEach((deet) => {
      deet.open = false;
    });
  });
  login?.addEventListener("focusin", (event) => {
    detailsElements.forEach((deet) => {
      deet.open = false;
    });
  });

  // Function to check the viewport width and add/remove attributes accordingly
  const html = document.querySelector("html");
  const navHeader = document.querySelector("nav.header");
  const offscreenElement = document.querySelector("#offscreen-nav");
  const offscreenClose = document.querySelector("#offscreen-nav .btn-close");
  const offscreenToggler = document.querySelector(".offscreen-toggler");
  const inertElements = document.querySelectorAll(
    "main, footer.site-footer, .site-banner, #skip, .department-logo, .nav-search, .offscreen-toggler"
  );

  // Create ResizeObserver for local-nav
  function checkHasNavOverflow(
    offscreenElement,
    navHeader,
    inertElements,
    offscreenToggler,
    offscreenClose
  ) {
    // let navHasOverflow;
    const navItemsArray = [];
    navItemsArray.length = 0;
    const localNavItems = document.querySelectorAll(
      "header .local-nav > ul > li"
    );
    localNavItems.forEach((navItem) => {
      navItemsArray.push(navItem.getBoundingClientRect().width);
    });
    // console.log(navItemsArray);
    const totalNavItemsWidth = navItemsArray.reduce(
      (accumulator, currentValue) => {
        return accumulator + currentValue;
      }
    );
    // console.log('totalNavItemsWidth', totalNavItemsWidth);

    const localNavObserver = new ResizeObserver((entries) => {
      entries.forEach((entry) => {
        let localNavWidth = entry.contentRect.width;
        if (totalNavItemsWidth > localNavWidth || totalNavItemsWidth === 0) {
          offscreenElement.setAttribute("popover", "auto");
          navHeader.classList.remove("full");
          offscreenToggler?.classList.remove("d-none");
          offscreenClose?.classList.remove("d-none");
        } else {
          offscreenElement.removeAttribute("popover");
          navHeader.classList.add("full");
          offscreenToggler?.classList.add("d-none");
          offscreenClose?.classList.add("d-none");

          // Remove the 'inert' attribute regardless of popover state (since full nav will show)
          inertElements.forEach((element) => {
            element.removeAttribute("inert");
          });
        }
      });
    });

    // Attach ResizeObserver
    const localNav = document.querySelector(".local-nav");
    localNavObserver.observe(localNav);
  }

  function setOffscreenState() {
    if (offscreenElement) {
      if (html.clientWidth < 992) {
        // Set the menu to offscreen state
        offscreenElement.setAttribute("popover", "true");
        navHeader.classList.remove("full");
      } else {
        // Set the menu to full state (not offscreen)
        offscreenElement.removeAttribute("popover");
        navHeader.classList.add("full");

        // Remove the 'inert' attribute regardless of popover state (since viewport is larger)
        inertElements.forEach((element) => {
          element.removeAttribute("inert");
        });
      }
    }
  }

  // Check if the offscreen element popover is open using :popover-open pseudo-class
  offscreenElement.addEventListener("toggle", () => {
    if (offscreenElement.matches(":popover-open")) {
      offscreenClose.focus();
      inertElements.forEach((element) => {
        element.setAttribute("inert", "true");
      });
    } else {
      inertElements.forEach((element) => {
        element.removeAttribute("inert");
      });
    }
  });

  // Attach the event listener to detect changes in the viewport size
  window.addEventListener("resize", setOffscreenState);

  // Call the function once to set the initial state
  setOffscreenState(html, offscreenElement, navHeader, inertElements);
  checkHasNavOverflow(
    offscreenElement,
    navHeader,
    inertElements,
    offscreenToggler,
    offscreenClose
  );
</script>
  • facebook

  • Instagram

  • Twitter

  • LinkedIn

  • YouTube

  • Accessibility
  • Privacy Policy
  • Contact Us
Sign up for our newsletter
ICPSR

© 2025 The Regents of the University of Michigan. ICPSR is part of the Institute for Social Research at the University of Michigan.