Tray Navigation (Overlay)

‹ Back

This is the overlay variant of mobile tray navigation.

Scaffolding the menu

The menu requires the following markup to get started. Some of the classes used may need to change depending on implementation.


  <!-- The container element that gets moved around when opening the overlay tray to give the illusion of keeping the scroll position -->
  <div data-tray-scroll-positioner>

    <!-- The element that gets darkened off when the overlay is open -->
    <!-- Feel free to move eg. the header out of this element so that it doesn't get darkened off if you have a sticky header -->
    <div data-tray-overlay-darken>

      <!-- The container for the overlay itself, this is where the navigation will appear -->
      <div data-tray-overlay>
        <button data-tray-close title="Close menu">Close</button>

      <!-- Example header containing toggle button -->
      <header role="banner">
        <button title="Open menu" data-tray-button>Toggle menu</button>

      <!-- Your main content area -->
      <main role="main" id="main"></main>

      <!-- Your footer -->
      <footer role="contentinfo"></footer>



Any element (preferably a button) that has the data-attribute data-tray-button will act as a toggle to show or hide the overlay tray when clicked.

Any element (again, preferably a button) that has the data-attribute data-tray-close will close the overlay when clicked.

As with most Ornament components, there is a public API, Ornament.C.OverlayTray which has functions to open/close/toggle the overlay on command. Feel free to use these methods to build out custom functionality.

Callbacks and customisation

Transition callbacks

There are callbacks implemented throughout the show/hide cycle:

  • Ornament.C.OverlayTray.beforeOpen()
  • Ornament.C.OverlayTray.afterOpen()
  • Ornament.C.OverlayTray.beforeClose()
  • Ornament.C.OverlayTray.afterClose()

Focus on open

By default, the component will focus on the first focusable element in the overlay when opened. You can override this functionality and have it focus on something specific with Ornament.C.OverlayTray.focusTrap.firstAfterOpen, which should be a single element.

An implementation might look like this:

var $searchField = document.querySelector("[data-my-search-field]");
Ornament.C.OverlayTray.focusTrap.firstAfterOpen = $searchField;

Notes on accessibility

The overlay component tries to meet the best practicies for accessibility:

  • When the overlay is opened, the element that is focused will be stored, so that when the overlay is closed focus can be restored to the last focused element.
  • When the overlay is open, all tabbing will be locked to the overlay. The user will not be able to tab out of the overlay. Tab order is restored when the overlay is closed. Tabbing (and reverse-tabbing) will loop back around so that the tabbing feels natural.

Visible on desktop

By default, this component assumes you have a seperate desktop navigation.

If you would like to have the navigation visible on desktop and only hidden on mobile there are a few changes you need to make.

[data-tray-overlay] {
  // Make sure it's visible on desktop
  display: block;
  visibility: visible;

  @include media-query($tray-breakpoint) {
    // Make sure it goes back to being untabbable at the breakpoint it hides
    visibility: hidden;

Depending on the scroll and positioning behaviour you may need to remove overflows and positioning properties on desktop.

If the user opens the mobile menu on mobile, then switches back to the desktop without closing the menu, the user will have their tab focusing locked to the overlay. You can get around this by setting the Ornament.C.OverlayTray.breakTabLockAt variable to the same value as your $tray-breakpoint. If $tray-breakpoint is the same as your $breakpoint-header, feel free to use:

// Remove tab focus lock on desktop
Ornament.C.OverlayTray.breakTabLockAt = Ornament.breakpoints.mobileHeader;