How to Improve ergonomy of your JavaScript/HTML5/CSS3 Windows 8.1 apps with the new navigation bar control

Windows 8.1 added a cool new control to WinJS: the navigation bar. This controls can be really helpful when it comes to organize the navigation inside your application. It allows you to create chapters and sub-chapters and then it helps the user to get access to all parts of your application.

For instance, here is the navigation bar of Urzagatherer:

Implementing the navigation bar

This bar is created using the following HTML code:

<div id="navBar" data-win-control="WinJS.UI.NavBar">
        <div id="navMenu" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'homeLink', icon: 'home' }" 
                                                           data-win-res="{winControl: {label:'Home'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'toolsGroup', icon: 'repair', splitButton: 'true' }" 
                                                           data-win-res="{winControl: {label:'Tools'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'optionsGroup', icon: 'settings', splitButton: 'true' }" 
                                                           data-win-res="{winControl: {label:'Options'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'statisticsLink', icon: 'paste' }" 
                                                           data-win-res="{winControl: {label:'Statistics'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'searchLink', icon: 'find' }" 
                                                           data-win-res="{winControl: {label:'AdvancedSearch'}}"></div>
        </div>
        <div id="searchZone">
            <div id="searchButton" class="win-searchbox-button searchglyph"></div>
            <div id="searchBox" class="SearchBox" data-win-control="WinJS.UI.SearchBox"></div>
        </div>
    </div>

A navigation bar (WinJS.UI.Navbar) contains some WinJS.UI.NavBarContainer which in turn contains WinJS.UI.NavBarCommand.

The navigation bar can also contain basic controls such as the search box here in my example.

The NavBarCommand can use “splitButton = true” to specify it will contain a sub-level. For instance, here is the declaration for the flyout that will be used as su-level for the Tools button:

<div id="toolsGroupFlyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ placement: 'bottom' }">
        <div id="toolsGroupNavBarContainer" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'listsLink', icon: 'list' }" 
                                                           data-win-res="{winControl: {label:'Lists'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'decksLink', icon: 'calendarweek' }" 
                                                           data-win-res="{winControl: {label:'Decks'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'lifeCountersLink', icon: 'trim' }" 
                                                           data-win-res="{winControl: {label:'LifeCounters'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'myCardsLink', icon: 'paste' }" 
                                                           data-win-res="{winControl: {label:'AllExceptMissing'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'newsLink', icon: 'globe' }" 
                                                           data-win-res="{winControl: {label:'News'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'slideshowLink', icon: 'slideshow' }" 
                                                           data-win-res="{winControl: {label:'slideshow'}}"></div>
        </div>
    </div>

You will need to add some JavaScript code in order to connect everything.

First of all, here is the code for the non-splitted buttons:

document.querySelector('#navBar').addEventListener('invoked', function (ev) {
    var navbarCommand = ev.detail.navbarCommand;

    switch (navbarCommand.id) {
        case "homeLink":
            while (nav.canGoBack) {
                nav.back();
            }
            break;
        case "statisticsLink":
            nav.navigate("/pages/collectionStatistics/collectionStatistics.html", {});
            break;
        case "searchLink":
            nav.navigate("/pages/advancedsearch/advancedsearch.html", {});
            break;
    }
});

Using the navbarCommand.id, you can determine which button was pushed and then react accordingly.

To work with the sub-menus, you have to connect to the splittoggle event of the NavBarContainer.

Using this event, you will handle the opening and the closing of the flyout used as sub-menu:

navMenu.addEventListener('splittoggle', function (ev) {
    var flyout;
    // Choose the right flyout 
    if (ev.detail.index == 2) {
        flyout = document.getElementById("optionsGroupFlyout").winControl;
    } else {
        flyout = document.getElementById("toolsGroupFlyout").winControl;
    }

    var navbarCommand = ev.detail.navbarCommand;
    if (ev.detail.opened) {
        flyout.show(navbarCommand.element);
        var subNavBarContainer = flyout.element.querySelector('.win-navbarcontainer');
        if (subNavBarContainer) {
            // Switching the navbarcontainer from display none to display block requires 
            // forceLayout in case there was a pending measure.
            subNavBarContainer.winControl.forceLayout();
            // Reset back to the first item:
            subNavBarContainer.currentIndex = 0;
        }
        flyout.addEventListener('beforehide', go);
    } else {
        flyout.removeEventListener('beforehide', go);
        flyout.hide();
    }

    function go() {
        flyout.removeEventListener('beforehide', go);
        navbarCommand.splitOpened = false;
    }
});

Eventually, you have to handle the click for items inside the sub-menu with a regular invoked event:

document.querySelector('#optionsGroupNavBarContainer').addEventListener('invoked', function (ev) {
                        var navbarCommand = ev.detail.navbarCommand;

                        switch (navbarCommand.id) {
                            case "slideShowButton":
                                setSlideShow();
                                break;
                            case "dataButton":
                                document.getElementById("databaseDiv").winControl.show();
                                break;
                            case "settingsButton":
                                document.getElementById("settingsDiv").winControl.show();
                                break;
                            case 'whatsnewButton':
                                document.getElementById("hintsDiv").winControl.show();
                                break;
                            case 'aboutButton':
                                document.getElementById("aboutDiv").winControl.show();
                                break;
                            case 'donateButton2':

                                donate();
                                break;
                        }
                    });

So to summarize you have to:

  • Declare a WinJS.UI.NavBar
  • Declare a WinJS.UI.NavBarContainer
  • Add some WinJS.UI.NavBarCommand to the container
  • Declare flyouts for sub-menus
  • Add code when button’s code is invoked
  • Handle the display of sub-menus using splittoggle event

Helping users discover your UI (and for instance the navigation bar)

Windows 8 modern apps have revolutionized the way windows communicates with users. All the chrome was removed to leave all the screen available for application’s content. However, this can lead your users to have some problems finding your navigation bar because they must be aware of the ways they can use to make it appears:

  • Right click with the mouse
  • Using the top or bottom edge gesture

That is why, based on feedbacks I got from my own users, I suggest you to add a small hint link this (the red drawings are not part of the image):

This small button is just here to indicate to users that more options are available. When the user clicks on this button, the following code can be executed to display the navigation bar:

// Hint
document.getElementById("navBarHint").onclick = function () {
    document.querySelector('#navBar').winControl.show();
};

This tips was also used by some Bing apps such as “Mail” (see the bottom bar)

I hope you will like the navigation bar and used it to improve your apps for Windows 8.1!