Multi Level Sidebar Menu jQuery

Multi Level Sidebar Menu jQuery

Multi level sidebar menu jQuery is a JavaScript library for creating multi-level, mobile-first, completely reachable off-canvas multi-level navigations using ARIA. It supports never-ending submenu basics nesting.

The hc-offcanvas-nav slides out from the left or right side of the webpage when switched, overlay or expands submenus when a parent menu is opened.

Multi level sidebar menu jQuery has many features.

  • Touch swipe gestures
  • No dependencies
  • Full ARIA keyboard support
  • Different navigation positions
  • Never-ending submenu basics nesting
  • Supple and simple markup
  • A number of visible Options, Methods and Events
  • Multi-level menu support
  • Custom content inside menu items
  • Push and Slide DOM elements of choice
  • Cross-browser compatibility
  • It depends on ARIA Design pattern for Dialogs
  • It can be closed using Esc

How to Install

This package can be installed with.

npm: npm install --save hc-offcanvas-nav

Including HC Off-canvas Nav

Script tag

<script src="/path/to/hc-offcanvas-nav.js?x49956"></script>

Webpack/Browserify

In the script, including HC Off-canvas Nav will usually look like this:

const hcOffcanvasNav = require('hc-offcanvas-nav');

Babel

import hcOffcanvasNav from 'hc-offcanvas-nav';

AMD (Asynchronous Module Definition)

If using AMD, the module will be automatically defined as hcOffcanvasNav.

How to use Use Multi level sidebar menu jQuery

Be sure to call HC-Sticky once your menu element is available in the DOM.

Vanilla JS

document.addEventListener('DOMContentLoaded', function() {

  var Nav = new hcOffcanvasNav('#main-nav', {
    disableAt: 1024,
    customToggle: '.toggle',
    navTitle: 'All Categories',
    levelTitles: true,
    levelTitleAsBack: true
  });

});

jQuery

jQuery(document).ready(function($) {

  $('#main-nav').hcOffcanvasNav({
    disableAt: 1024,
    customToggle: $('.toggle'),
    navTitle: 'All Categories',
    levelTitles: true,
    levelTitleAsBack: true
  });

});

HC Off-canvas Nav work as a jQuery plugin, so jQuery has to be worldwide window object property. You’ll need to be careful when using it in grouping with Browserify, Babel, Webpack and jQuery.

Example HTML menu structure

<nav id="main-nav">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li>
      <a href="#">Services</a>
      <ul>
        <li>
          <a href="#">Hosting</a>
          <ul>
            <li><a href="#">Private Server</a></li>
            <li><a href="#">Managed Hosting</a></li>
          </ul>
        </li>
        <li><a href="#">Domains</a></li>
        <li><a href="#">Websites</a></li>
      </ul>
    </li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
jQuery Multi Level Sidebar Menu with Submenu

Options

PropertyDefaultTypeDescription
width280int / strWidth of the nav. Used for left and right positions.
height'auto'int / strHeight of the nav. Used for top and bottom positions.
disableAtfalseint / boolResolution above which to hide the offcanvas menu, and show the original.
pushContentnullstr / Element objContent element (string selector or HTML Element object) that will be pushed when the navigation is open.
expandedfalseboolInitialize menu in expanded mode. It won’t push content.
position'left'strPosition on which the menu will open. Available options: 'left''right''top' and 'bottom'.
swipeGesturestrueboolEnable open/close swipe gestures like in native apps. Works only for left and right positions.
levelOpen'overlap'strSubmenu levels open effect. Available options: 'overlap''expand''none' or false.
levelSpacing40intIf levels are overlaped, this is the spacing between them, if they are expanding or always open, this is the text indent of the submenus.
levelTitlestrueboolShow titles for submenus, which is the parent item name. Works only for overlaped levels.
navTitlenullstrMain navigation (first level) title.
navClass''strCustom navigation class.
disableBodytrueboolDisable body scroll when navigation is open.
closeOpenLevelstrueboolShould all open sub levels be closed when the nav closes.
closeActiveLevelfalseboolShould initially active sub level (see data-nav-active) be cleared when the nav closes.
closeOnClicktrueboolClose the navigation when links are clicked.
customTogglenullstr / Element objCustom navigation toggle element.
insertClosetruebool / intInsert navigation close button. You can also use an integer representing 0-based index that will be the position of the button in the list. Negative numbers are also supported.
insertBacktruebool / intInsert back buttons to submenus. You can also use an integer representing 0-based index that will be the position of the button in the list. Negative numbers are also supported. Works only for overlaped levels.
labelClose'Close'str, Element objLabel for the close button (which can also be HTML element object).
labelBack'Back'strLabel for the back buttons.
ariaLabels{...}objLabels for the ARIA attributes. If using HC Off-canvas Nav in different language than English, you should translate all the properties. See the next section.
levelTitleAsBacktrueboolUse level titles as back labels.
rtlfalseboolSet the content direction to right-to-left.
bodyInsert'prepend'strChoose to prepend or append navigation to body.
keepClassestrueboolShould original menus and their items classes be preserved or excluded.
removeOriginalNavfalseboolRemove original menu from the DOM. Don’t use this if planning to update the nav!

ARIA labels for the aria-label attributes on specific elements which will provide a text alternative to the elements that have no visible text on the screen.

ariaLabels: {
  open:     'Open Menu',
  close:    'Close Menu',
  submenu:  'Submenu'
}

Methods of Usage

The HC Off-canvas Nav API gives some incorporate methods to control the offcanvas and are publicly accessible to all active instances.

Vanilla JS

var Nav = new hcOffcanvasNav();

jQuery

var $nav = $('#main-nav').hcOffcanvasNav();
var Nav = $nav.data('hcOffcanvasNav');

.getSettings()

Returns current settings.

var currentSettings = Nav.getSettings();

.isOpen()

Checks if the nav is open, and returns boolean.

if (Nav.isOpen()) {
  // do something
}

.update(options, updateDOM)

Updates just the itemized settings with the new ones.

Nav.update({
  disableAt: 1024,
  navTitle: 'All pages'
});

Updates nav DOM. You don’t have to pass empty settings object. The method is smart. Use this when original nav has been altered.

Nav.update(true);

Updates both settings and nav DOM. Use this when original nav was altered and you want to update some specific settings as well.

Nav.update({
  disableAt: 1024,
  navTitle: 'All pages'
}, true);

.open(level, index)

Opens the nav if closed.

Nav.open();

Open the nav along with a specific sub menu. Each level sub menu has its own index that is relative to that level, not the parent menu.

Nav.open(2, 1);

Above code will open to the nested menu in the example structure bellow:

<nav>
  <ul><!-- Level: 0 -->
    <li></li>
    <li>
      <ul><!-- Level: 1, Index 0 -->
        <li>
          <ul><!-- Level: 2, Index: 0 -->
            <li></li>
            <li></li>
          </ul>
        </li>
        <li>

          <ul><!-- Level: 2, Index: 1 -->
            <li></li>
            <li></li>
          </ul>

        </li>
      </ul>
    </li>
    <li></li>
    <li>
      <ul><!-- Level: 1, Index 1 -->
        <li>
          <ul><!-- Level: 2, Index: 2 -->
            <li></li>
            <li></li>
          </ul>
        </li>
        <li></li>
      </ul>
    </li>
  </ul>
</nav>

.close()

Closes the nav if open.

Nav.close();

.on(eventName, cb)

Attach Event listener to the nav.

Nav.on('close', function() {
  // do something on close
});

.off(eventName, cb)

Remove Event listener from the nav.

// remove specific function
Nav.off('close', onCloseFunction);

// remove all event listeners
Nav.off('close');

Events

EventDescription
openTriggers each time when the nav is opened.
open.levelTriggers each time when any level is opened.
closeTriggers each time when the nav is closed.
close.onceTriggers only the first time the nav is closed, and than it detaches itself.
close.levelTriggers each time when any level is closed.

All events return to Event object as first argument, and the plugin Settings object as second argument.
open.level and close.level return the newly opened level and index under the Event.data property.

// change nav open position after each close
Nav.on('close', function(e, settings) {
  Nav.update({
    position: settings.position === 'left' ? 'right' : 'left'
  });
});

// will change nav open position only once
Nav.on('close.once', function(e, settings) {
  Nav.update({
    position: settings.position === 'left' ? 'right' : 'left'
  });
});

Nav.on('open.level', (e, settings) => {
  localStorage.setItem('NavLevel', e.data.currentLevel);
  localStorage.setItem('NavIndex', e.data.currentIndex);
});

Nav.on('close.level', (e, settings) => {
  localStorage.setItem('NavLevel', e.data.currentLevel);
  localStorage.setItem('NavIndex', e.data.currentIndex);
})

Data Attributes

AttrAcceptsHTML ElementDescription
data-nav-active<ul>,<li>The next time nav opens it will open specified sub menu (or sub menu whose parent &lt;li&gt; element has the attribute). Works with expanded option.
data-nav-highlight<li>Highlight list item.
data-nav-custom-content<li>Attached on the list items. Will clone item’s content as is.
data-nav-closebool<a>Attached on the item links. Tells the nav if it needs to be closed on click or not.
<nav id="main-nav">
  <ul>
    <li data-nav-custom-content>
      <div>Some custom content</div>
    </li>
    <li data-nav-highlight><a href="#">Home</a></li>
    <li data-nav-active>
      <a href="#">About</a>
      <ul data-nav-active><!-- or active attribute can be here -->
        <li><a href="#">Team</a></li>
        <li><a href="#">Project</a></li>
        <li><a href="#">Services</a></li>
      </ul>
    </li>
    <li><a href="#">Contact</a></li>
    <li><a data-nav-close="false" href="#">Add Page</a></li>
  </ul>
</nav>

WordPress data attributes integration

To make your WordPress theme nav data ready, just place this code to your functions.php file. It will work out of the box. Don’t assign this custom Walker to your wp_nav_menu arguments. You don’t need to be worry if your own custom Walker is already used, this code will take care of the whole thing.

/*
 * Adds menu data support for HC Off-canvas Nav
 */

$hc_nav_menu_walker;

class HC_Walker_Nav_Menu extends Walker_Nav_Menu {

  public function start_lvl(&$output, $depth = 0, $args = array()) {
    global $hc_nav_menu_walker;
    $hc_nav_menu_walker->start_lvl($output, $depth, $args);
  }

  public function end_lvl(&$output, $depth = 0, $args = array()) {
    global $hc_nav_menu_walker;
    $hc_nav_menu_walker->end_lvl($output, $depth, $args);
  }

  public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    global $hc_nav_menu_walker;

    $item_output = '';

    $hc_nav_menu_walker->start_el($item_output, $item, $depth, $args, $id);

    if ($item->current_item_parent) {
      $item_output = preg_replace('/<li/', '<li data-nav-active', $item_output, 1);
    }

    if ($item->current) {
      $item_output = preg_replace('/<li/', '<li data-nav-highlight', $item_output, 1);
    }

    $output .= $item_output;
  }

  public function end_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    global $hc_nav_menu_walker;
    $hc_nav_menu_walker->end_el($output, $item, $depth, $args, $id);
  }
}

add_filter('wp_nav_menu_args', function($args) {
  global $hc_nav_menu_walker;

  if (!empty($args['walker'])) {
    $hc_nav_menu_walker = $args['walker'];
  }
  else {
    $hc_nav_menu_walker = new Walker_Nav_Menu();
  }

  $args['walker'] = new HC_Walker_Nav_Menu();

  return $args;
});

Dev Building

This package comes with Gulp. The following tasks are available:

  • default compiles the JS and SCSS into /dist and builds the demos into /docs.
  • demo executes default task and opens the demo html page.
  • watch watches source JS and SCSS files and builds them automatically whenever you save.

You can pass a --dev command if you don’t want the compiled JS and Css to be minified.

File Information

File Size200 KB
Last UpdateToday
Published Date2 Years Ago
LicenseMIT

Your email address will not be published. Required fields are marked *

More Stories
JavaScript Image Parallax Scroll – SimpleParallax
JavaScript Image Parallax Scroll – SimpleParallax