🗺️ Site Navigation
An HTML Custom Element to make site nav a bit easier.
Currently this package is intended to be added to your project with npm/yarn,
and included in your project, likely through webpack. There are other ways you
could include it (running webpack on this repo to generate files in
for instance), but the following is the recommended process (i.e. the one I've
$ npm i @murmurcreative/site-navigation
// main.js, or a script that will be run on all pages import '@murmurcreative/site-navigation';
If you're using webpack, you'll need to make sure that your loaders for
css aren't ignoring the
site-navigation directory (often webpack
configuration will ignore
node_modules, which will prevent
from getting picked up.) As an example, in the default
roots' Sage, make the following changes:
// resources/assets/build/webpack.config.js test: /\.js$/, exclude: [/node_modules(?![/|\\](bootstrap|foundation-sites))/], //...to this: test: /\.js$/, exclude: [/node_modules(?![/|\\](bootstrap|foundation-sites|site-navigation))/],
When used, site-navigation will look at the content you put inside it to build a menu. An example might look this this:
<site-navigation> <nav> <button data-toggle>Open</button> <div data-drawer> <ul> <li> <a href="/home/">Home</a> </li> <li> <a href="/page-1/">Page One</a> </li> <li> <a href="/page-2/">Page Two</a> <button data-toggle>Open</button> <ul> <li> <a href="/page-2/page-3/">Page Three</a> <button data-toggle>Open</button> <ul> <li> <a href="/page-2/page-3/page-4/">Page Four</a> </li> </ul> </li> </ul> </li> </ul> </div> </nav> </site-navigation>
Note: The above reflects a recommended layout: a
<nav>nested in the master
<div>s as top-level Drawer(s) and
<ul>s as nested Drawers. This is the easiest to understand, and the most accessible. site-navigation is flexible enough to support many different layouts, however, so long as you follow the rules below.
A Drawer is a section of content that will be hidden and shown when its associated Toggle is clicked. A Drawer can contain whatever you want it to (even other Drawers!) but it will usually contain a list of navigational links. The rules for setting up a Drawer are as follows:
- Your Drawer can be any block-level element, but it must meet at least one of the following
- Have the attribute
- Directly follow a Toggle
- Have the attribute
- Your Drawer must be directly preceeded by a Toggle.
Drawers represent the single source of truth about their state: Toggles take their state from their associated Drawers. This means that if you want to determine or set the state of a Drawer programmatically, you should do so through the Drawer itself, not a Toggle. site-navigation only recognizes Drawers and Toggles in pairs: If you have only one, it will simple ignore that element.
Opening/Closing Drawers Programatically
There are three functions attached to each Drawer which site-navigation uses internally to handle opening and closing Drawers:
toggleDrawer()- Switches the state of the Drawer.
openDrawer()- Opens the Drawer. Has no effect if the Drawer is already open.
closeDrawer()- Closes the Drawer. Has no effect if the Drawer is already closed.
Each of these functions also has a "silent" variant, which means that the event will not bubble up to the parent event: It will only fire on itself. This can be useful if you're doing something that manipulates drawer state based on the state of another drawer (otherwise you can get a lot of recursion).
// Let's assume you have a Drawer with the ID `location-list`, which is currently closed. document.getElementByID(`location-list`).toggleDrawer(); // The Drawer is now open. document.getElementByID(`location-list`).openDrawer(); // The state of the Drawer has not changed. document.getElementByID(`location-list`).closeDrawer(); // The Drawer is now closed. document.getElementByID(`location-list`).openDrawerSilently(); // The drawer is now open, but the parent <site-navigation> was // not notified.
Toggles are the buttons used to open and close Drawers. They must obey the following rules:
- Have the attribute
- Directly preceed a Drawer
- Be a
Note: Technically, a toggle can be any element which will dispatch the
clickevent when clicked, but in practice and for accessibility reasons they should almost always be
... <li> <a href="/contact">Contact Us</a> <button data-toggle>Open</button> <ul>...</ul> </li> ...
... <li> <button data-toggle>Open</button> <a href="/contact">Contact Us</a> <ul>...</ul> </li> ...
<button> does not immediately preceed the
... <li> <a href="/contact">Contact Us</a> <ul>...</ul> </li> ...
There is no
<button> for the
Drawers dispatch events when their state should change, which all other parts of
site-navigation hook into to do their thing. These events bubble up all the way to the
<site-navigation> root element, but stop there (to avoid polluting the wider DOM). You can
listen on the root element or to individual Drawers for the
detail property on the event includes the element that displatched the event (
and the state to which the Drawer is being set (