How to brand your ListView

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

In Branding your Windows Store apps, we told you how to incorporate the essence of your brand in your app while adhering to the Microsoft design principles. We covered seven aspects of brand design: color, icons, images, grid, layout, logo, and typography.

Here we talk about how to customize your app's landing page using these techniques:

This topic shows you how to start from the Visual Studio Grid App template and modify it to create landing pages like these:

The Contoso Bakery landing page

The Contoso Food Truck example

Prerequisites

When to use a ListView

Your first decision is which controls to use on your landing page. For a list of HTML and Windows Library for JavaScript controls, see the Controls list.

If you want to present a collection of data as a series of items, such as an email list, search results, or a catalog of items for purchase, use a ListView.

The ListView displays items in a list or grid layout. Most landing pages that display items use the ListView control's grid layout, because it automatically overflows and scrolls horizontally. You can customize the items in the ListView by modifying the itemTemplate used to display the items.

The CSS3 Grid Layout and the Windows 8 grid system

The grid system is an important part of the Windows 8 look and feel, and helps achieve visual unity across different apps and features. With the grid layout you can divide space for elements on the page and easily align elements to the grid.

In our examples, we also use the Cascading Style Sheets, Level 3 (CSS3) Grid Layout, which is different from the ListView control's grid layout. The CSS3 Grid Layout provides general purpose grid styling for a wide variety of uses, while the ListView is only for displaying collections of data. With the CSS3 Grid Layout you can cleanly lay out your apps easily align elements to the grid.

Contoso French Bakery example

Let’s look at the default Visual Studio Grid App template and compare it to the Contoso French Bakery example from Branding your Windows Store apps. Here is a screen shot of the Grid App template:

An app using the Grid App template

Let’s compare this to the Contoso French Bakery landing page from Branding your Windows Store apps. The Contoso French Bakery lays out its items in a customized way that emphasizes the Contoso brand.

The Contoso Bakery landing page

While the Contoso French Bakery landing page looks very different from the Grid App template, the difference comes from just a few HTML/CSS modifications. In this example, we assume that the items are interactive and that selecting an item brings the user to a group detail page with a selection of types of macaroons, cupcakes, and so on. A ListView that uses the grid layout is appropriate control for this landing page.

To convert the Grid App template into the Contoso landing page, we need to change the size of the item templates, increase the image sizes, and add item descriptions.

  1. In Visual Studio, create a new app that uses the Grid App template.

  2. Update the HTML itemtemplate in groupedItems.html. The main change from the default itemtemplate is to add a third heading element to display each item description.

        <div class="itemtemplate" data-win-control="WinJS.Binding.Template">
            <div class="item">
                <img class="item-image" src="#" 
                     data-win-bind="src: backgroundImage; alt: title" />
                <div class="item-text">
                    <h3 class="item-title" data-win-bind="textContent: title"></h3>
                    <h6 class="item-subtitle win-type-ellipsis" 
                        data-win-bind="textContent: subtitle"></h6>
                    <h6 class="item-detail" data-win-bind="textContent: description"></h6>
                </div>
            </div>
        </div>
    
  3. Now we update the styles in groupedItems.css. The main change to groupedItems.css is to move the text div below the image, rather than overlaying it on top of the image, and to add another row to the grid for the item detail element.

    .groupeditemspage .groupeditemslist .win-horizontal.win-viewport .win-surface {
            margin-bottom: 60px;
            /* Decreased margin */
            margin-left: 35px;
            margin-right: 115px;
    }   
    .groupeditemspage .groupeditemslist .item {
           /* Changed row size and item size, centered text and changed text color */ 
            -ms-grid-columns: 1fr;
            -ms-grid-rows: 1fr 1280px;
            display: -ms-grid;
            height: 600px500px;
            width: 350px;
            text-align: center;
            color: rgb(160,160,160);
    
        }
    
            .groupeditemspage .groupeditemslist .item .item-image {
                   /* Increased image size and altered padding */
                height: 340px;
                width: 340px;
                padding: 0px 5px 20px 5px;
            }
    
            .groupeditemspage .groupeditemslist .item .item-text {
                /* Added a row to the grid and changed height and padding */
                -ms-grid-row: 2;
                -ms-grid-rows: 30px 21px 1fr;
                display: -ms-grid;
                padding: 30px 15px 2px 15px;
                height: 150px;
            }
    
                .groupeditemspage .groupeditemslist .item .item-text .item-title {
                    /* Changed font color */
                    -ms-grid-row: 1;
                    overflow: hidden;
                    font-size: 16pt;
                    color: rgb(200,200,200);
                }
    
                .groupeditemspage .groupeditemslist .item .item-text .item-subtitle {
                    -ms-grid-row: 2;
                }
                .groupeditemspage .groupeditemslist .item .item-text .item-detail {
                    /* All new CSS for the detail text */
                    -ms-grid-row: 3;
                    overflow:hidden;
                    padding-top: 20px;
                    height: 60px;
                    margin-left: 30px;
                    margin-right: 30px;
                }
    
  4. Remove the group headers from data.js. (The easiest way is to simply delete the title of each group).

With these changes, your app now looks like this:

The updated app

Add some images and change the background and title, and you’ve created the Contoso French Bakery landing page!

Contoso Food Truck example

In the next example, we create the Contoso Food Truck landing page from the Grid App template.

The Contoso Food Truck example

The Contoso Food Truck landing page draws the user in with eye-catching images in a variety of sizes.

Unlike the previous example, this landing page requires some JavaScript additions to the template, primarily to add the logic to give the items in the ListView different sizes. Again, we assume that the items in the landing page are interactive and that choosing one takes the user to a detail view of that item. A ListView that uses the grid layout is the right tool for the job. Once again, we use the Grid App template as our starting point.

To use multi-sized items, we must first decide on a minimum base unit. We use this unit to build all of the grid items, and so all grid items must be composed of multiples of this grid size. The smallest dimension of one of the items in the next image is the height of the items in the “Near Me” section, which is about 80px. There is more flexibility with the horizontal dimension. For simplicity, we use 80px for the horizontal dimension too.

This image shows what the base unit looks like (the red square) compared to several actual items.

Base item size

When calculating item sizes, each item size must be equal to a multiple of the base unit, plus the padding in between units. The formula is:

item sizeₓ = m * base unit sizeₓ + (m -1) * item padding

item sizey = m * base unit sizey + (m -1) * item paddingy

where m is a positive integer, and x and y denote the x and y dimensions of the item size and the item padding.

If the base size is too small relative to the items, it will degrade your app's performance. As a rule of thumb, the size of any item should not be more than a few base units in either direction.

  1. In Visual Studio, create a new app that uses the Grid App template.

  2. In groupedItems.html, create a new item template named multisizebaseitemtemplate. This item template is more or less the same as the default item template, but with an “item-description” header added so we can include the item description in addition to the title and subtitle on the landing page.

      <!-- Template tutorial HTML -->
        <div class="multisizebaseitemtemplate" data-win-control="WinJS.Binding.Template">
            <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
            <div class="item-overlay">
                <h4 class="item-title" data-win-bind="textContent: title"></h4>
                <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
                <h6 class="item-description" data-win-bind="textContent: description"></h6>
            </div>
        </div>
    
  3. In groupedItems.js, create a templating function named multisizeItemTemplateRenderer before the PageControl definition (ui.Pages.define).

    We use this function to render the ListView items. It's this function that determines which items use which item template. We assign it to the ListView control's itemTemplate property in a later step.

     function multisizeItemTemplateRenderer(itemPromise) {
            return itemPromise.then(function (currentItem) {
                var content;
                // Grab the default item template used on the groupeditems page.
                content = document.querySelector(".multisizebaseitemtemplate");
                var result = content.cloneNode(true);
    
                // Change the CSS class of the item depending on the group, then set the size in CSS.
                switch (currentItem.groupKey) {
                    case "group1":
                        {
                            // For the first item, use the largest template.
                            if (currentItem.index == 0) {
                                result.className = "largeitemtemplate"
                            }
                            // Use the mediumlarge template for the second item
                            else if (currentItem.index == 2) {
                                result.className = "mediumlargeitemtemplate"
                            }
                            // Use the medium template for the third item, and any other items
                            else {
                                result.className = "mediumitemtemplate"
                            }
                            break;
                        }
                    default:
                        {
                            // Use the small template for the second group
                            result.className = "smallitemtemplate"
                        }
                }
                // Because we used a WinJS template, we need to strip off some attributes 
                // for it to render.
                result.attributes.removeNamedItem("data-win-control");
                result.attributes.removeNamedItem("style");
                result.style.overflow = "hidden";
    
                // Because we're doing the rendering, we need to put the data into the item.
                // We can't use data binding.
                result.querySelector(".item-image").src = currentItem.data.backgroundImage;
                result.querySelector(".item-title").textContent = currentItem.data.title;
                result.querySelector(".item-subtitle").textContent = currentItem.data.subtitle;
                result.querySelector(".item-description").textContent = currentItem.data.description;
                return result;
            });
        }
    
  4. In groupedItems.js, add the groupInfo function, also outside the page definition. This function tells the ListView to use multi-sized items in the view, and indicates the base size of the items. The base size is the smallest item shown in the list. Other items must be multiples of this size for the layouts to work correctly.

     function groupInfo() {
        return {
            enableCellSpanning: true,
            cellWidth: 80,
            cellHeight: 80
        };
     }
    
  5. Now we need to hook these new functions up to the ListView control.

    1. In groupedItems.js, change the _initializeLayout function so that we show a flat list of groups.

      // Add the itemTemplate parameter as shown.
      _initializeLayout: function (listView, viewState, itemTemplate) {
          if (viewState === appViewState.snapped) {
              listView.itemDataSource = Data.groups.dataSource;
              listView.groupDataSource = null;
      
              // Add the following line of code.
              listView.itemTemplate = itemTemplate;
      
              listView.layout = new ui.ListLayout();
          } else {
      
                      listView.itemDataSource = Data.items.dataSource;
                      listView.groupDataSource = Data.groups.dataSource;
                      listView.layout = new ui.GridLayout({ groupHeaderPosition: "top" });
      
              // Add the following two lines of code.
              listView.itemTemplate = multisizeItemTemplateRenderer;
              listView.layout = new ui.GridLayout({ groupInfo: groupInfo, groupHeaderPosition: "top" });
          }
      },
      
    2. Remove the line that assigns an item template to the ListView, and make the changes indicated by the comments in this code.

      ready: function (element, options) {
          var listView = element.querySelector(".groupeditemslist").winControl;
      
          // Add the next line of code to retrieve the item template. 
          var itemTemplate = element.querySelector(".itemtemplate");
      
          listView.groupHeaderTemplate = element.querySelector(".headerTemplate");
      
          listView.oniteminvoked = this.itemInvoked.bind(this);
              listView.itemTemplate = element.querySelector(".itemtemplate");
      
          // Change the last argument of the _initializeLayout function to itemTemplate.
          this._initializeLayout(listView, appView.value, itemTemplate);
          listView.element.focus();
       },
      
      // This function updates the page layout in response to viewState changes.
      updateLayout: function (element, viewState, lastViewState) {
          var listView = element.querySelector(".groupeditemslist").winControl;
      
          // Add the next line of code to retrieve the item template.
          var itemTemplate = element.querySelector(".itemtemplate");
      
          if (lastViewState !== viewState) {
              if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
                  var handler = function (e) {
                      listView.removeEventListener("contentanimating", handler, false);
                      e.preventDefault();
                  }
                  listView.addEventListener("contentanimating", handler, false);
      
                  // Change this line to pass through the item template.
                  this._initializeLayout(listView, viewState, itemTemplate);
              }
          }
      },
      
      
  6. Next, we need to add styling for the items to groupedItems.css. To style the items as shown in the previous image, we need 4 CSS classes for the 4 different item templates on the landing page. Name the 4 classes smallitemtemplate, mediumitemtemplate, mediumlargeitemtemplate, and largeitemtemplate. The next CSS mostly positions the overlay and text relative to the image and sizes each item appropriately. In some cases, certain elements are collapsed, because not all templates use all of the elements in the item template. Add this CSS just before the first @media screen CSS line.

    /* Generic styling */
    .groupeditemspage .groupeditemslist .item-overlay {
        -ms-grid-row: 2;
    }
    .groupeditemspage .groupeditemslist .item-overlay .item-description {
        visibility:collapse;
    }
    
    /* Small item template */
    .groupeditemspage .groupeditemslist .smallitemtemplate {
        width: 440px;
        height: 80px;
        overflow: hidden;
    
    }
    .groupeditemspage .groupeditemslist .smallitemtemplate .item-image {
        height: 80px;
        width: 80px;
    }
    .groupeditemspage .groupeditemslist .smallitemtemplate .item-overlay {
       opacity: 0;
    }
    .groupeditemspage .groupeditemslist .smallitemtemplate .item-overlay .item-title {
        position: absolute; 
        top: -5px;
        padding-left: 90px;
        font-size: 11pt;
    }
    .groupeditemspage .groupeditemslist .smallitemtemplate .item-overlay .item-subtitle {
        position: absolute; 
        top: 15px;
        padding-left: 90px;
        font-size: 9pt;
    }
    .groupeditemspage .groupeditemslist .smallitemtemplate .item-overlay .item-description {
        position: absolute; 
        top: 35px;
        padding-left: 90px;
        font-size: 9pt;
        visibility: visible;
        width: 360px;
        overflow-wrap: normal;
        text-overflow: initial;
    }
    
    /* Medium item template */
    .groupeditemspage .groupeditemslist .mediumitemtemplate {
        width: 260px;
        height: 170px;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr 30px;
        display: -ms-grid;
        overflow: hidden;
    }      
    .groupeditemspage .groupeditemslist .mediumitemtemplate .item-overlay .item-title {
        padding-top: 5px;
        padding-left: 10px;
    }
    .groupeditemspage .groupeditemslist .mediumitemtemplate .item-overlay .item-title {
        font-size: 14px;
    }
    .groupeditemspage .groupeditemslist .mediumitemtemplate .item-overlay .item-subtitle {
        visibility: collapse;
    }   
    
    /* Medium-large item template */
    .groupeditemspage .groupeditemslist .mediumlargeitemtemplate {
        width: 260px;
        height: 350px;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr 30px;
        display: -ms-grid;
        overflow: hidden;
    }
    .groupeditemspage .groupeditemslist .mediumlargeitemtemplate .item-overlay .item-title {
        padding-top: 5px;
        padding-left: 10px;
        font-size: 14px;
    }
    
    .groupeditemspage .groupeditemslist .mediumlargeitemtemplate .item-overlay .item-subtitle {
        visibility: collapse;
    }   
    
    /* Large item template */
    .groupeditemspage .groupeditemslist .largeitemtemplate {
        width: 440px;
        height: 530px;
        overflow: hidden;
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr 90px;
        display: -ms-grid;
    }
    .groupeditemspage .groupeditemslist .largeitemtemplate .item-overlay {
        -ms-grid-row: 2;
        -ms-grid-rows: 1fr 21px;
        display: -ms-grid;
        padding: 6px 15px 2px 15px;
    }
    .groupeditemspage .groupeditemslist .largeitemtemplate .item-subtitle{
        -ms-grid-row: 2;
    }
    
    
  7. In the @media screen and (-ms-view-state: fullscreen-landscape), screen and (-ms-view-state: fullscreen-portrait), screen and (-ms-view-state: filled) rule, change the first CSS style to the following. This CSS code makes the overlay opaque and removes the "item" class.

     .groupeditemspage .groupeditemslist .item-overlay {
            background: rgba(0,0,0,1);
        }
    
  8. Change the first .groupeditemspage .groupeditemslist .win-horizontal.win-viewport .win-surface style in groupedItems.css to this.

        .groupeditemspage .groupeditemslist .win-horizontal.win-viewport .win-surface {
            margin-bottom: 60px;
            margin-left: 45px;
            margin-right: 115px;
        }
    

    This CSS code changes margin-bottom to "50px" to account for slightly larger items.

After making these changes, launch your app. It will look like this:

The updated app

Add pictures, change the background, text, and overlay color, and you get the Contoso Food Truck landing page.

More creative sizes and templates

There are more ways to customize your item templates than what we've shown here. For example, this landing page achieves a balanced look by using two item sizes and three different templates.

Another customized landing page

This landing page's base unit is the size of the smallest item. The first item in each group is 2x3 base units and has a template that places the title and description underneath the image. The next items in the group are 1x1 units and overlay the title and description onto the image. The third template is for items that don't have images.

Adding ListView item animations

In the Start screen, live tiles present the user with up-to-date pictures and text that provide info at a glance. An app’s landing page can do the same, if appropriate, using the WinJS Animation Library.

This example makes the first item on the landing page update with a new image every 4 seconds, the same amount of time as used in the Start screen. We use the WinJS peek animation, which is the same animation as tiles in Start use.

  1. In Visual Studio, create a new app that uses the Grid App template.

  2. In groupedItems.html, modify the item template to include a second image, which will be used for the animation.

        <div class="itemtemplate" data-win-control="WinJS.Binding.Template">
            <div class="item">
                <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
                <img class="item-image-new" src="#" data-win-bind="src: backgroundImage; alt: title" />
                <div class="item-overlay">
                    <h4 class="item-title" data-win-bind="textContent: title"></h4>
                    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
                </div>
            </div>
        </div>
    
  3. In groupedItems.css, modify the CSS to position the second image below the initial image. This enables us to animate the new image into place starting from the bottom of the item. We need to make both items use relative positioning so that we can change their position before we kick off the animation. The first and third CSS styles already exist in groupedItems.css and just need to be modified. The second CSS style is new.

            /* Update this CSS style. */
            .groupeditemspage .groupeditemslist .item .item-image {
                -ms-grid-row-span: 2;
                position:relative;
            }
    
            /* Add this CSS style. */
            .groupeditemspage .groupeditemslist .item .item-image-new {
                -ms-grid-row-span: 2;
                position:relative;
                top: 250px;
            }
    
            /* Update this CSS style. */
            .groupeditemspage .groupeditemslist .item .item-overlay {
                -ms-grid-row: 2;
                -ms-grid-rows: 1fr 21px;
                display: -ms-grid;
                padding: 6px 15px 2px 15px;
                position:relative;
            }
    
  4. In groupedItems.js, add this code to the ready function to trigger a new item animation every 4 seconds.

                setInterval(function () { changeImage() } , 4000);
    
  5. In groupedItems.js, add this code outside the page definition. The first variable definitions point to the different images used by the Grid App template. Add the peekTile function to play the Windows Library for JavaScript peek animation. Add the changeImage function to update the images before playing the animation. In this example, we play the animation only for the first item in the ListView.

        // Define images
        var darkGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY3B0cPoPAANMAcOba1BlAAAAAElFTkSuQmCC";
        var lightGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
        var mediumGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
    
        // Play the Peek animation
        function peekTile(tile1, tile2) {
            // Create peek animation
            var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
    
            // Reposition tiles to their desired post-animation position
            tile1.style.top = "-250px";
            tile2.style.top = "0px";
    
            // Execute animation
            peekAnimation.execute();
        }
    
       function changeImage() {
            // Get the two image elements
            var images = document.querySelector(".item-image");
            var imagesNew = document.querySelector(".item-image-new"); 
    
            // Swap out the old image source and choose the new image source
            images.src = imagesNew.src;
            if (images.src == lightGray)
                imagesNew.src = mediumGray;
            else if (images.src == mediumGray)
                imagesNew.src = darkGray;
            else
                imagesNew.src = lightGray;
    
            // Reset the elements for the pre-animation position and trigger the animation
            images.style.top = "0px";
            imagesNew.style.top = "250px";
            peekTile(images, imagesNew);
        };
    

    Congratulations, you've added custom item animations to your ListView!

ListView

Quickstart: Adding a ListView

Styling the ListView and its items