menu
Menu
Mobify DevCenter
search_icon_focus

Nav

The Nav component is a panel that holds the site navigation, providing the user with a way to access all product categories and other important pages. It provides an arbitrarily nested navigation tree that can be used to manage transitions between navigation nodes.

The state of the navigation tree is shared with child components through context, making it easy to build custom navigation UIs. For simple cases, a set of default components are provided. Subscribe to changes through the onPathChange prop in order to make changes to the navigation state of the app.

Related components: Nav, NavHeader, NavItem, NavMenu, NavSlider, MegaMenu, and MegaMenuItem.

JavaScript import

import Nav from 'progressive-web-sdk/dist/components/nav/'

SCSS import

@import 'node_modules/progressive-web-sdk/dist/components/nav/base';

Props table

Name & DescriptionTypeDefault
children
The element's children.
nodenone
className
Additional CSS classes to give to the element.
stringnone
path
The currently selected path in the navigation.
string'/'
root
The structure of the navigation as a JS object.
shape{title: '', path: '/'}
onPathChange

Callback invoked when the selected path changes. The callback is defined as of type:

(path: String, isLeaf: Boolean, trigger: String, originalPath: String) => any

The trigger argument designates what type of action triggered the path change. It can be one of the following values: mouseEnter, mouseLeave, touchEnd, focus, blur, or click.

func() => undefined

More on the root prop

The root prop is an object that represents the complete navigation tree. It’s passed to the Nav component in its entirety, even though only a small portion of it is rendered at a time. Its basic structure can be described like this:

root = {
title: '', // string, required
path: '', // string, required
type: '', // string
children: [] // array (of root objects)
}

Even though the path value is just a plain string, it does require / characters to determine the depth of the navigation node. For example, the top-most node path is likely just /, while second-level nodes are /something/ and have two / characters which makes it depth 2. Third-level nodes /foo/bar/ have three / characters making it depth 3, and so on.

The children key is optional, and it has a required format: it must be an array of root objects. There is no limit to the depth of this structure. Children root objects can have their own array of root objects, and so on.

See the example usages further below to see what root objects might look like.

More on the onPathChange prop

onPathChange is a function callback used as a hook to trigger behavior when the navigation path changes. A navigation path change is triggered whenever the user interacts with a NavItem. It takes four arguments:

  • path (string): the current navigation item’s path (may be modified to deduplicate non-unique paths in the Nav).
  • isLeaf (boolean): whether the current navigation item is a leaf (see the Example With Nested Navigation And Leafs section below to learn about leafs).
  • trigger (string): the interaction that triggered the navigation to the current item. Can be one of: mouseEnter, mouseLeave, touchEnd, focus, blur or click.
  • originalPath (optional) (string): the original, unmodified path of the current navigation item.

Ultimately it’s up to the developer to decide when and how route changes occur, but a common pattern is the following:

const onPathChange = (path, isLeaf, trigger) => {
setState({path: path})
if (isLeaf) {
window.location.href = path
}
}

The example usages further below show how to apply the callback.

Basic example

This example shows the bare minimum needed to render the Nav component. This example, while simple, is non-functional and not very useful by itself. Gradually more complex examples with more useful functionality, are provided below.

Example of the Nav component that uses a child NavMenu:

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

With MegaMenu

This example shows the bare minimum needed to render the Nav component. This example, while simple, is non-functional and not very useful by itself. Gradually more complex examples, with more useful functionality, are provided below.

Example of the Nav component that uses a child MegaMenu:

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

Enabling route changes

In the example above, you may notice that the component’s links don’t actually function at all. In order to enable the links to navigate, we must supply a callback to the onPathChange prop.

Also, by tracking the current active path, we can have the Nav component highlight it. This is done by passing the active path to the path prop.

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

With nested navigation and leafs

A very common navigation pattern is the nested navigation. This usually implies that the navigational structure of an app consists of multiple tiers of depth. This can be achieved with the Navigation component by passing arrays to the children keys in the root object.

By introducing children to the navigation tree, our Nav component inherits some new behavior: clicking on a navigation item with children will animate in a new “page” of navigation items. With this pattern, a user can narrow in on the page they want to visit very quickly.

In a nested navigation, items at the end of a navigation branch (one that has no children) can be thought of us a “leaf”. It’s usually these leaf items that actually trigger a route change. As such, the onPathChange callback is passed isLeaf as an argument to detect whether the user clicked on a leaf. The developer can then use this to determine how they want to trigger route changes.

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

With nav header and controls

In the previous example, you might notice that it’s not possible to move the navigation back to a previous page. That’s because the example is missing a crucial part of the navigation UI: the NavHeader sub-component.

A common feature of the navigation component is to have a header section dedicated to displaying navigational meta data, such as the active navigation level, back and close buttons. You can achieve this by including NavHeader as a child to Nav. See the example below for the most simple (non-functional) use case. See the subsequent example for a fully functional use case.

If you wondered earlier why the root object’s first tier included a title key, now you see why: because it’s used in the NavHeader component!

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

Here is the fully functional example of the NavHeader:

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

Custom animations

To customize how the Nav component animates as it transitions from page to page, you can pass custom configurations to the NavHeader and/or the NavMenu components’ prop called animationProperties. See either the NavHeader or NavMenu for details.

The item factory

It’s common for developers to customize how the navigation items are rendered. This can be done using the NavMenu component’s itemFactory callback. For examples of this, see the NavMenu component.

Complex example

Below is an example that takes everything discussed above to create a single, complex use case. As mentioned above, see either the NavHeader or NavMenu for details on the item factory and custom animations.

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

Duplicate paths

The Nav component was originally designed to render a navigation tree in which every item contained a unique path or URL. We’ve upgraded the Nav to handle cases where users want to include items with duplicate paths in the same menu. The Nav does this by automatically de-duplicating paths on the items you pass it.

Path modification for duplicate paths

If the navigation tree contains nodes with duplicate paths, paths are modified by appending ’#‘s to the end of the path. For example, consider the following navigation tree:

const root = {
title: 'My Store',
path: '/',
children: [
{title: 'child1', path: '/child/'},
{title: 'child2', path: '/child/'},
{title: 'child3', path: '/child/'}
]
}

All the children of the ‘root’ element in the above navigation tree have identical paths. Their paths will be deduplicated as:

  • path of root: ’/’
  • path of child1: ‘/child/’
  • path of child2: ‘/child/#’
  • path of child3: ‘/child/##’

Handling warnings relating to “duplicate paths in the Nav”

If you are using duplicate paths in your navigation system, you might see a warning like: Your Nav contains duplicate paths. Make sure you change your onPathChange callback to use originalPath when changing routes...

If you see a warning relating to duplicate paths like the message above, you’ll need to upgrade your onPathChange function to take a fourth parameter containing the original, unmodified path, like this:

amex-hint[icon]/bag/dark[icon]/basket/dark[icon]/caret/bottom/dark[icon]/caret/left/dark[icon]/caret/right/dark[icon]/caret/top/dark[icon]/cart/dark[icon]/caution/darkAmericanExpressCredit CardUnionPaydankortdinersclubDiscoverinterpayjcbmaestroMasterCarduatpVisavisa-electron[icon]/check/dark[icon]/chevron/bottom/dark[icon]/chevron/left/dark[icon]/chevron/right/dark[icon]/chevron/top/dark[icon]/close/darkvisa-mc-hint@3x[icon]/edit/dark[icon]/help/dark[icon]/info/dark[icon]/like/dark[icon]/location/dark[icon]/lock/dark[icon]/menu/dark[icon]/minus/dark[icon]/more/dark[icon]/payment/dark[icon]/plus/dark[icon]/review/dark[icon]/search/dark[icon]/shipping/dark[icon]/social/facebook/dark[icon]/social/google-plus/dark[icon]/social/instagram/dark[icon]/social/pinterest/dark[icon]/social/twitter/dark[icon]/social/yelp/dark[icon]/social/youtube/dark[icon]/star/dark[icon]/trash/dark[icon]/user/dark[icon]/zoom/dark

If a navigation tree that has duplicate paths is passed into the ‘Nav’ component without using the modified onPathChange callback, then the ‘path’ that you would get from the onPathChange callback would be the deduplicated path (the path appended with #s).