@morsedigital/vanilla-responsive-navigation

Responsive navigation module written in vanilla JavaScript

Stats

StarsIssuesVersionUpdatedCreatedSize
@morsedigital/vanilla-responsive-navigation
1.4.03 years ago5 years agoMinified + gzip package size for @morsedigital/vanilla-responsive-navigation in KB

Readme

vanilla-responsive-navigation

Synopsis

A responsive navigation module written in vanilla JavaScript.

Installation

npm install @morsedigital/vanilla-responsive-navigation

Running tests

npm run test

Example Instantiation

const ResponsiveNavigationClass = require('@morsedigital/vanilla-responsive-navigation');

const primaryNavigation = new ResponsiveNavigationClass(
  'primary-navigation',
  {
    list_id: 'primary-navigation-list'
    , toggle_id: 'primary-navigation-toggle'
  }
);

if (primaryNavigation && primaryNavigation.hasOwnProperty('config')){
  primaryNavigation._init();
}

Configuration

A new instance of ResponsiveNavigationClass can contain the following in its configuration object:

new ResponsiveNavigationClass({
  dropdownClass: // String. Class for a list item which contains a child ul. Default is "dropdown-parent"
  , flyout: // Boolean. Determines whether or not a class is added to the body when the navigation is visible. If you have more than one navigation on the page, make sure you're not setting this to true everywhere. Default is false
  , list_id: // String. Id for the main ul in the navigation. Default is "responsive-navigation-list"
  , toggle_id: // String. Id for the main toggle. Default is "responsive-navigation-toggle"
  , toggle_mobile_id: // String. Id for the mobile toggle. This is only needed if flyout has been set to true. Default is null
});

Example HTML structure (non-flyout)

<nav class="primary-navigation" id="primary-navigation" role="navigation">
  <a href="#" id="primary-navigation-toggle" class="primary-navigation-toggle" aria-controls="navigation" aria-expanded="false" aria-hidden="true" aria-label="navigation menu" role="button">
    Toggle menu
  </a>
  <ul id="primary-navigation-list" class="primary-navigation-list">
    <li>
      <a href="/regular-link">Regular link</a>
    </li>
    <li class="dropdown-parent">
      <a href="#">Parent link</a>
      <ul>
        <li>
          <a href="/child-link-1">Child link 1</a>
        </li>
        <li>
          <a href="/child-link-2">Child link 2</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

Example HTML structure (flyout)

<nav class="primary-navigation" id="primary-navigation" role="navigation">
  <a href="#" id="primary-navigation-toggle" class="primary-navigation-toggle" aria-controls="navigation" aria-expanded="false" aria-hidden="true" aria-label="navigation menu" role="button">
    Toggle menu
  </a>
  <ul id="primary-navigation-list" class="primary-navigation-list">
    <li class="primary-navigation-header">
      <!-- This is the mobile toggle which is used to close the navigation when it's open -->
      <a href="#" id="primary-nav-toggle-mobile">
        Toggle menu (flyout)
      </a>
    </li>
    <li>
      <a href="/regular-link">Regular link</a>
    </li>
    <li class="dropdown-parent">
      <a href="#">Parent link</a>
      <ul>
        <li>
          <a href="/child-link-1">Child link 1</a>
        </li>
        <li>
          <a href="/child-link-2">Child link 2</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

CSS

As a bare minimum, you'll require the following, or similar CSS:

(non-flyout)

.primary-nav-list {
  display: none;

  &.open {
    display: block;
  }
}

(Flyout)

Non-responsive

(base styles)

body {
  position: relative;
}
Responsive

(styles which are applied at different breakpoints)

@include breakpoint($mobile-breakpoint) {
  body {
    &.nav-open {
      .primary-nav-list {
        width: percentage(2/3);
      }
    }
  }

  .primary-nav-list {
    right: -(percentage(2/3));
    width: percentage(2/3);
  }
}

@include breakpoint($mobile-and-tablet-breakpoint) {
  body {
    &.nav-open {
      .primary-navigation-list {
        right: 0;
      }
    }
  }

  .primary-navigation-list {
    position: fixed;
    top: 0;
    @include transition(right 0.2s ease-in-out);

    li {
      float: left;
      width: 100%;
    }

    .dropdown {
      display: none;
    }

    .dropdown-parent {
      & > a {
        position: relative;

        &:after {
          content: "\25b6";
          position: absolute;
          top: 15px;
          right: 10px;
        }

        &.open {
          &:after {
            content: "\25bc";
          }
        }
      }
    }
  }

  .primary-navigation-toggle {
    display: block;
    float: right;
    position: relative;
    top: 10px;
  }
}

@include breakpoint($tablet-breakpoint) {
  body {
    &.nav-open {
      .primary-nav-list {
        width: percentage(1/2);
      }
    }
  }

  .primary-nav-list {
    right: -(percentage(1/2));
    width: percentage(1/2);
  }
}

@include breakpoint($desktop-breakpoint) {
  .primary-navigation-list {
    .dropdown {
      display: none;
      overflow: hidden;
      position: absolute;
      left: 0;
      top: 100%;

      li {
        clear: both;
        white-space: nowrap;
        width: 100%;
      }
    }

    .dropdown-parent {
      position: relative;

      &:hover {
        .dropdown {
          display: block !important; /* Needs !important to override JS */
        }
      }
    }
  }

  .primary-navigation-header, .primary-navigation-toggle {
    display: none;
  }
}

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.