jQuery Mobile - Tab Navigation


This is one of several jQuery Mobile samples. Please refer to the jQuery Mobile and jQuery overview articles for related background information.

The source code for this sample can be found here: https://github.com/gomobile/sample-jqm-tab-nav or download the Intel® XDK to check out all the HTML5 Samples.

This sample is a multi-page scaffold using tab-based navigation. For other page navigation styles, please see the list- and springboard-based navigation samples.

Additionally, this sample demonstrates how to create a custom options menu widget that maintains state across page transitions, and how to dynamically inject widgets into the DOM.

Tab-Based Navigation

The main landing page presents tabs of pages to navigate to. This is implemented using jQuery Mobile's navbar, which is a page-width bar comprised of 1-5 equal-width inline buttons. The navbar is represented as an unordered HTML list wrapped in a container div with a data-role="navbar" attribute. Each list item contains the link to the destination page, and the corresponding text to be displayed. The list item representing the currently viewed page is applied with a ui-btn-active class to highlight the corresponding tab with the active state color, and a ui-state-persist class so that the active state is restored each time navigating back to this page. The navbar constitutes a fixed and persistent footer, which remains in place across intra-page scrolling and inter-page navigation, respectively. This footer is kept visible at all times, overriding jQuery Mobile's default tapToggle behavior to hide and show the footer whenever the screen is tapped. (In practice, the default tapToggle behavior often resulted in a disappearing navbar when trying to change tabs on a mobile device.)

<div data-role="footer" data-id="tabnav-footer" data-position="fixed">
    <div data-role="navbar">
            <li><a href="#home" class="ui-btn-active ui-state-persist">One</a></li>
            <li><a href="#page2">Two</a></li>
            <li><a href="#page3">Three</a></li>
/* keep footer visible at all times */
$(':jqmData(role=footer)').fixedtoolbar( { tapToggle: false } );

Custom Options Menu Widget

This sample showcases a custom options menu widget based on jQuery Mobile's checkboxes form element. To achieve a compact drop-down menu look, the jQuery Mobile data-role="controlgroup" attribute is used to group the checkboxes without extra spacing in between, the data-mini="true" attribute is used to specify a compressed styling with smaller fonts, and custom CSS is used to limit the width to 120px. The options menu is positioned at the top right corner of the in-view content area, right under the fixed-positioned header toolbar button used to show and hide the menu. The vertical positioning of the menu is dynamically determined, after the height of the header and the position of the content area have been determined by the HTML5 runtime layout process.

<div class="optionsMenu">
    <form action="#" method="get">
        <div data-role="fieldcontain">
            <fieldset data-role="controlgroup" data-mini="true">
                <input type="checkbox" name="option1" id="option1"/>
                    <label for="option1">Option 1</label>
                <input type="checkbox" name="option2" id="option2"/>
                    <label for="option2">Option 2</label>
/* custom styling of options menu (position & width) */
.optionsMenu {
    /* custom narrow width to look like a menu */
    width: 120px;
    /* top right corner under options button (1px margin; set top dynamically) */
    position: fixed;
    right: 1px;
/* calculate vertical position of menu */
initPosition: function($page) {
    /* menu should be almost aligned with content area at the top (1px gap) */
    top = $page.find(':jqmData(role=content)').position().top + 1;
    /* update position for current page's menu widget */
    $page.find('.optionsMenu').css('top', top);

Creation from Template

Since jQuery Mobile does not innately allow for widgets that persist across multiple pages (with the exception of persistent headers and footers), this sample creates one options menu widget per page. Rather than manually replicating the same HTML widget code for each page, the widget is specified once in an HTML template, then copied and inserted dynamically into each page. This allows for more readable and maintainable code, and less room for copy-and-paste errors. The template is embedded within the main HTML code as a script tag of the unknown type "text/html". This enables the template to be formatted and maintained with the rest of the HTML code, while staying invisible to the HTML5 runtime and accessible to the JavaScript* code. Once created and inserted into the DOM, the widget triggers its create event to inform the jQuery Mobile framework of its existence, so that it can be initialized with the appropriate jQuery Mobile styling and behavior.

<!-- options menu template (hide in unknown script tag type) -->
<script type="text/html" id="optionsMenuTmpl">
    <div class="optionsMenu">
        <!-- see above -->
/* create one options menu per page */
function($page) {
    /* copy HTML code for options menu from template */
        /* insert into dom */
        /* get jQuery Mobile to process widget */

Maintaining State Across Pages

To maintain the illusion that all options menu widgets are one of the same, the checkbox state is kept consistent across the different pages' widgets. This sample uses an array, options, to lazily synchronize the checkbox state across each page transition. Upon leaving the current page (i.e. pagebeforehide event fired), the sample saves the checked state of each checkbox into the options array. Upon entering a new page (i.e. pagebeforeshow event fired), the sample updates the checked state of each checkbox from the options array, then informs the jQuery Mobile framework via checkboxradio('refresh') to apply the styling for the updated state.

/* state of the four options to be synched across page transitions */
/* (all initialized to be unchecked) */
options: [false, false, false, false]
/* save state of options (upon leaving the current page) */
saveState: function($optionsMenu) {
        .each(function(index) {
            options[index] = $(this).is(':checked');
/* update options with latest state (upon entering a new page) */
reconcileState: function($optionsMenu) {
        .each(function(index) {
            /* draw check marks for selected options */
            if (options[index]) {
                $(this).attr('checked', true).checkboxradio('refresh');
            /* clear check marks for unselected options */
            else {
                $(this).attr('checked', false).checkboxradio('refresh');

Event-Based Actions

The options menu acts as a drop-down menu for the options button in the header toolbar. The menu is shown when the button is pressed, then hidden when the button is pressed again. The menu and button do not know about each other, as to establish a clean separation of concerns. Rather, they communicate in a decoupled manner via jQuery's global $.event channel. The button triggers a custom toggleOptionsMenu event whenever it is pressed. The menu for the current page subscribes to the toggleOptionsMenu event, and toggles its own visibility upon receiving the event.

/* header toolbar button clicked */
$optionsBtn.on('click', function() {
/* the options menu for the current page subscribes to the toggle event */
$optionsMenu.on('toggleOptionsMenu', function() {
    if ($(this).is(':visible')) {
    } else {

Configuring jQuery Mobile Defaults

As soon as it is loaded, the jQuery Mobile framework triggers the mobileinit event on the document object, then automatically applies many markup enhancements. Therefore, to override jQuery Mobile defaults before these enhancements occur, bind any custom configuration code to the mobileinit event before loading jQuery Mobile. For example, this sample uses config.js to use no animated page transitions by default.

<script type="text/javascript" src="vendor/jquery/jquery-1.8.0.js"></script>
<script type="text/javascript" src="app/config.js"></script>
<script type="text/javascript" src="vendor/jqm/jquery.mobile-1.1.1.js"></script>
/* config.js: */
$(document).bind('mobileinit', function () {
    $.mobile.defaultPageTransition = 'none';

Devices Tested:

  • Samsung Galaxy S* II smartphone (Google Android* 2.3.5, 480 x 800 pixels, hdpi)
  • Lava Xolo X900* smartphone (Android 2.3.7, 600 x 1024 pixels, hdpi)
  • Motorola Droid* Razr M smartphone (Android 4.0.4, 540 x 960 pixels, hdpi)
  • Asus Google Nexus* 7 tablet (Android 4.1.1; display: 7 inches, 1280 x 800 pixels, tvdpi)
  • Amazon Kindle Fire* 2 tablet (v.10.1.3 based on Android 4.0; display: 7 inches, 1024 x 600 pixels, mdpi)
  • Apple iPod Touch* 4th gen mobile device (Apple iOS* 4.3.1, 640 x 960 pixels, retina) !
  • Apple iPod Touch 4th gen mobile device (iOS 6.0, 640 x 960 pixels, retina)
  • Apple iPad* 2 tablet (iOS 5.1.1, 1024 x 768 pixels, non-retina)

! fixed positioning unsupported

Download project assets on github

Download Now

For more complete information about compiler optimizations, see our Optimization Notice.