/scrollnav

A dependency free JavaScript plugin for auto generating single page navigation

Primary LanguageJavaScriptMIT LicenseMIT

This project is currently archived. I unfortunately don't have the time to maintain it. Thanks to everyone that contributed along the way, it wouldn't have been possible without you.

npm Build Status Codecov license

Introduction

scrollnav.js is a small (2.4kb gzipped), dependency free JavaScript plugin for auto generating single page navigation with active highlighting. Useful for creating a Table of Contents for a large document (think Wikis), navigation for a single page website, or anything else you might think of.

scrollnav works by scanning a block of content for section landmarks (typically heading elements) and generating a list of links from those landmarks. It then tracks the scroll location of the document and highlights the appropriate link. While previous versions injected wrappers within the content, the current version (ver 3) takes a much lighter approach, only changing the DOM as necessary. Visit the live demo at scrollnav.com to see for yourself.

Browser Compatibility

To keep scrollnav small, default support starts with ES6 compatible browsers. To support ES5 compatible browsers you must provide your own polyfills or rely on a third party library like pollyfills.io. I personally use the following polyfill.io feature parameters to support scrollnav in IE 10 & 11.

<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=default,NodeList.prototype.forEach,Array.prototype.includes"></script>

To add your own polyfills you will need to build the project from source.

Getting Started

The compiled, production ready plugin is available in the dist directory. Please don't use the src directory unless you plan to build the entire source.

Install

Download

scrollnav@v3.0.2

<script src="[your assets directory]/scrollnav.min.umd.js"></script>

CDN

<script src="https://unpkg.com/scrollnav@3.0.2/dist/scrollnav.min.umd.js"></script>

Package manager

Yarn: yarn add scrollnav

It's the new hotness, it's also better at managing dependencies than all it's predecesors.

NPM: npm install scrollnav

Good'ol NPM, it's always there, except when it isn't. Things have settled down a bit, but it was dicey there for a while. Even still, there's a reason even Yarn uses the NPM registry.

Bower: bower install scrollnav --save

The folks from Bower no longer recommend using Bower. Luckily they've provided a guide on how to migrate to Yarn. If you don't want to or can't migrate, scrollnav will continue to be available on Bower as long as it continues to run.

Usage

scrollnav works by scanning the given HTML Node Element for section landmarks, by default h2 elements, that it then uses to generate the nav. If we were to look at a typical document, it might look like this:

  <div class="main-content">
    <h2>First section</h2>
    ...
    <h2>Second section</h2>
    ...
    <h2>Third section</h2>
    ...
  </div>

Initialize

First, initialize scrollnav with the HTML Element. In this example we'll use .querySelector() but you could also use .getElementByID() or .getElementByClassName().

const content = document.querySelector('.main-content');
scrollnav.init(content);

scrollnav will then loop through the the h2 elements, add an ID if they don't already have one, build the nav, and then inject it just before the content Node. The result for our example document would look like this:

<nav class="scroll-nav">
  <ol class="scroll-nav__list">
    <li class="scroll-nav__item">
      <a class="scroll-nav__link" href="#scroll-nav__1">
        First heading
      <a>
    </li>
    ...
  </ol>
</nav>
<div class="main-content">
  <h2 id="scroll-nav__1">First Heading</h2>
  ...
</div>

Styles

To keep the plugin simple there are no styles added to the navigation, that's all up to you (view the demo site for exmaples of the most common use cases). The nav structure provides BEM Methodology class names for each of the elements to provide consistent styling hooks (for a good overview read MindBEMding - getting your head 'round BEM syntax). As the user scrolls the document, scrollnav adds a scroll-nav__item--active modifier for the item's relative section that currently intersects with the activation threshold (enable debug mode to highlight the threshold).

Settings and options

scrollnav includes some default settings that work for most situations, but if your project requires a bit more customization, scrollnav can most likely meet those. To modify either, pass in a single object (include settings and options as one object) as the second argument like this:

  scrollnav.init(content, {
    key: value
  });

Default settings

The following settings are editable to overwrite the default.

{
  sections: 'selector',
  // string
  //
  // Sets the querySelector for the content's section landmarks, by default
  // it's 'h2'.

  insertTarget: targetNode,
  // HTML Node
  //
  // Sets the target Node for injecting the navigation, by default it's the
  // content Node passed to scrollnav.

  insertLocation: 'relativeLocation'
  // string
  //
  // Sets the injection location relative to the insertTarget, by default it's
  // 'before'.
  //
  // available options are 'append', 'prepend', 'after', or 'before'

  easingStyle: 'easingName',
  // string
  //
  // Sets the easing type for the scroll animation that is triggered by the
  // click event on a nav item, by default it's 'easeOutQuad'.
  //
  // available options are 'linear' 'easeInQuad', 'easeOutQuad',
  // 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic',
  // 'easeInQuart', 'easeOutQuart', 'easeInOutQuart', 'easeInQuint',
  // 'easeOutQuint', easeInOutQuint

  updateHistory: true
  // boolean
  //
  // Sets the history behavior when a nav item is clicked, by default it's true
}

Additional options

These additional options are editable but are not set by default.

{
  subSections: '...',
  // string
  //
  // Sets the querySelector for the content's sub-section landmarks.

  onScroll: function() {...},
  // function
  //
  // Sets the callback to be triggered after the window scrolls when triggered
  // by the click event on a nav item.

  onInit: function() {...},
  // function
  //
  // Sets the callback to be triggered after the .init() method has completed.

  onUpdatePositions: function() {...},
  // function
  //
  // Sets the callback to be triggered after the .updatePositions() method
  // has completed.

  onDestroy: function() {...},
  // function
  //
  // Sets the callback to be triggered after the .destroy() method has
  // completed.

  debug: false
  // boolean
  //
  // Enables scrollnav's built in debug mode to log errors to the console and
  // display the active area threshold on screen, helpful for when you've hit a
  // snag you can't easily identify.
}

Available methods

In addition to the .init() method scrollnav provides two additional public methods.

destroy()

To remove the current instance of scrollnav call the destroy method. If you need to trigger a callback after scrollnav has been removed, use the onDestroy option described above (passed either in the original init or with the destroy method).

scrollnav.destroy();

updatePositions()

scrollnav doesn't track outside DOM changes. If your page's content is dynamic and updates after scrollnav is initialized you'll need to recalcuate the position data with the updatePositions method. If you need to trigger a callback after the position data has been recalculated, use the onUpdatePositions option described above (passed either in the original init or with the updatePositions method).

scrollnav.updatePositions();

Issues

Please read and understand the Contributing Guidelines prior to opening an issue. Ensuring your issue conforms to the guidelines gives it a better chance I'll be able to help address it.

Questions

For questions about using scrollnav in your own project, your best bet is to post it to Stack Overflow. The community there is great at lending a hand and can often respond faster than I can, plus it becomes searchable for future developers who may run into the same question. If you're still stuck, please feel free to reach out to me to ask for help or clarification, I'm @jimmynotim on Twitter.

Changelog

v3.0.2 is the current stable release. For detailed changes in each release please refer to the release notes. Please be sure you understand the changes before updating, v3 is a complete re-write of the plugin (as is v2 compared to v1 before it).

Contributions

scrollnav is built and maintained by James Wilson (@jimmynotjim). I wouldn't be able to continue this project without a lot of help from the Open Source community. I welcome feedback and enhancements, but first, please make sure to read the Contributing Guide.

Thank you to everyone who has already contributed to scrollnav!

License

scrollnav is Copyright © 2012-2018 James Wilson, released under the MIT license. This means you can re-create, edit or share the plugin as long as you maintain the same open licensing.