How to make app bars work with ListViews

Applies to Windows and Windows Phone

This how-to explains the interaction between the ListView and the app bar to support these scenarios while following the app bar best practices. Typically the ListView lets user pan collection of objects horizontally and select one of more of these objects to perform some actions. These actions are often exposed in the app bar.

Prerequisites

Instructions

Step 1: Maintain the app bar promises

  1. Invocation: if an app bar is present users should be able to invoke it or hide it via the standard mechanisms at any time:
    • Edge swipe
    • Win+Z
    • Right click
  2. If there is no command to be exposed until an object is selected, no app bar should be shown
  3. Commands that are present irrespective of selection should be in the global section of the app bar, with very few exceptions on the right of the app bar

Step 2: Support selection and multi-selection

  1. Show the app bar programmatically on selection.
  2. Set the app bar to sticky to support multi-selection.
  3. Show commands specific to selection in contextual section of the app bar (on the left except for very few exceptions).
  4. Show additional commands if needed when more than one object is selected (e.g. clear selection).
  5. Remove the sticky property when selections are cleared.
  6. Hide commands that are contextual to selection.

Here is the HTML for an app bar with commands.


<!-- AppBar with contextual commands for a ListView -->
<!-- BEGINTEMPLATE: Template code for AppBar -->
<div id="scenarioAppBar" data-win-control="WinJS.UI.AppBar">
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdAdd',label:'Add',icon:'add',section:'global',extraClass:'singleSelect',tooltip:'Add item'}"></button>
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdSelectAll',label:'Select All',icon:'selectall',section:'selection',extraClass:'multiSelect',tooltip:'Select All'}"></button>
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdClearSelection',label:'Clear Selection',icon:'clearselection',section:'selection',extraClass:'multiSelect',tooltip:'Clear Selection'}"></button>
    <hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'selection',extraClass:'multiSelect'}" />
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdDelete',label:'Delete',icon:'delete',section:'selection',extraClass:'multiSelect',tooltip:'Delete item'}"></button>
</div>
<!-- ENDTEMPLATE -->

When app bar is initialized, selection contextual commands are hidden.


function initAppBar() {
    var appBarDiv = document.getElementById("scenarioAppBar");
    var appBar    = document.getElementById("scenarioAppBar").winControl;
    // Add event listeners
    document.getElementById("cmdAdd").addEventListener("click", doClickAdd, false);
    document.getElementById("cmdDelete").addEventListener("click", doClickDelete, false);
    document.getElementById("cmdSelectAll").addEventListener("click", doClickSelectAll, false);
    document.getElementById("cmdClearSelection").addEventListener("click", doClickClearSelection, false);
    appBar.addEventListener("beforeshow", doAppBarShow, false);
    appBar.addEventListener("beforehide", doAppBarHide, false);        
    // Hide selection group of commands
    appBar.hideCommands(appBarDiv.querySelectorAll('.multiSelect'));
    // Disable AppBar until in full screen mode
    appBar.disabled = true;
} 

This function shows the app bar, sets it to sticky, and shows contextual commands upon selection.


function doSelectItem() {
    var appBarDiv = document.getElementById("scenarioAppBar");
    var appBar =    document.getElementById('scenarioAppBar').winControl;
    var listView =  document.getElementById("scenarioListView").winControl;
    var count = listView.selection.count();
    if (count > 0) {
        // Show selection commands in AppBar
        appBar.showCommands(appBarDiv.querySelectorAll('.multiSelect'));
        appBar.sticky = true;
        appBar.show();
    } else {
        // Hide selection commands in AppBar
        appBar.hide();
        appBar.hideCommands(appBarDiv.querySelectorAll('.multiSelect'));
        appBar.sticky = false;
    }
} 
 

Step 3: Adjust scrollbar position

To support scrolling while the app bar is visible, like for multi-selection, the scrollbar needs to be placed so that it is above the app bar. Because of localization, you should expect app bar button labels to be one line longer than English-only labels. When placing the scrollbar, you should account for that extra line. So for example, a single label app bar that is 88px tall for English should become 108 px tall with two lines labels.

Design your ListView so that the scrollbar has a 108px clearance for the app bar. Then adjust the position of the scroll bar so it's visible and in the right position depending on whether the app bar is present.


/* This function slides the ListView scrollbar into view if occluded by the AppBar (in sticky mode) */
function doAppBarShow() {
    var listView = document.getElementById("scenarioListView");
    var appBar = document.getElementById("scenarioAppBar");
    var appBarHeight = appBar.offsetHeight;
    // Move the scrollbar into view if appbar is sticky
    if (appBar.winControl.sticky) {
        var listViewTargetHeight = "calc(100% - " + appBarHeight + "px)";
        var transition = {
            property: 'height',
            duration: 367,
            timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
            to: listViewTargetHeight
        };
        WinJS.UI.executeTransition(listView, transition);
    }
}

/* This function slides the ListView scrollbar back to its original position */
function doAppBarHide() {
    var listView = document.getElementById("scenarioListView");
    var appBar = document.getElementById("scenarioAppBar");
    var appBarHeight = appBar.offsetHeight;
    // Move the scrollbar into view if appbar is sticky
    if (appBar.winControl.sticky) {
        var listViewTargetHeight = "100%";
        var transition = {
            property: 'height',
            duration: 367,
            timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
            to: listViewTargetHeight
        };
        WinJS.UI.executeTransition(listView, transition);
    }
} 

Step 4: Support scrolling and zooming.

To support zooming and vertical scrolling, you should place the app bar and LitView in peer divs and make sure zoom only applies to the ListView div and not the whole page.


<!-- Full screen container for ListView -->
<div id="scenarioFullscreen">
    <button id="scenarioHideListView">Hide ListView</button>
    <header aria-label="Header content" role="banner">
        <button id="scenarioBackButton" class="win-backbutton" aria-label="Back"></button>
        <div class="titlearea win-type-ellipsis">
            <h1 class="titlecontainer" tabindex="0">
                <span class="pagetitle">Ice cream</span>
            </h1>
        </div>
    </header>
    <section role="container">
        <div id="scenarioListView"
            data-win-control="WinJS.UI.ListView"
            data-win-options="{ itemTemplate: smallListIconTextTemplate, selectionMode: 'multi', tapBehavior: 'toggleSelect', swipeBehavior: 'select', layout: { type: WinJS.UI.GridLayout, maxRows: 4 }}" >
        </div>
    </section>
</div>    
<!-- AppBar with contextual commands for a ListView -->
<!-- BEGINTEMPLATE: Template code for AppBar -->
<div id="scenarioAppBar" data-win-control="WinJS.UI.AppBar">
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdAdd',label:'Add',icon:'add',section:'global',extraClass:'singleSelect',tooltip:'Add item'}"></button>
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdSelectAll',label:'Select All',icon:'selectall',section:'selection',extraClass:'multiSelect',tooltip:'Select All'}"></button>
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdClearSelection',label:'Clear Selection',icon:'clearselection',section:'selection',extraClass:'multiSelect',tooltip:'Clear Selection'}"></button>
    <hr     data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'selection',extraClass:'multiSelect'}" />
    <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdDelete',label:'Delete',icon:'delete',section:'selection',extraClass:'multiSelect',tooltip:'Delete item'}"></button>
</div>
<!-- ENDTEMPLATE --> 

Remarks

Interactions between list view and app bar are expected to be a common way to design apps. Follow these simple best practices and you can align with the recommended user experience.

 

 

Show:
© 2015 Microsoft