jQuery Mobile

Navigation Home

AJAX Navigation API

The AJAX navigation system allows for animated page transitions while preserving deep-linking and Back button support. Jump to section  

jQuery Mobile includes a navigation system to load pages into the DOM via AJAX, enhance the new content, then display pages with a rich set of animated page transitions. The navigation system uses progressive enhancement to automatically 'hijack' standard links and form submissions and route them as an AJAX request.

The back button is fully supported so pages, dialogs and popups all seamlessly work with the navigation system. There are features to prefetch & cache, dynamically inject, and script pages for advanced use cases.

A "page" in jQuery Mobile consists of an element with a data-role="page" attribute. Within the "page" container, any valid HTML markup can be used, but for typical pages in jQuery Mobile, the immediate children of a "page" are divs with data-roles of "header", "content", and "footer".

The baseline requirement for a page is only the page wrapper, the rest is optional. If a document doesn't even have a page wrapper, the framework will automatically wrap the contents of the body to create one.

Whenever a link is clicked or a form is submitted, that event is automatically intercepted by the AJAX nav system and is used to issue a AJAX request based on the href or form action instead of reloading the page. While the framework waits for the AJAX response, a loader overlay is displayed.

When the requested page loads, the jQuery Mobile parses the document for an element with the data-role="page" attribute and inserts that code into the DOM of the original page. Next, any widgets in the incoming page are enhanced to apply all the styles and behavior.

The rest of the incoming page is discarded so any scripts, stylesheets or other information in the will not be included. Reference the same set of stylesheets and scripts in the head of every pageand bind logic to the pageinit event (details below) to run necessary code when a specific page is created (which can be determined by its id attribute). ALternatively, include scripts at the end of the body element when no data-role=page element is defined, or inside the first data-role=page element.

Now that the requested page is now in the DOM and enhanced, the page transition is applied and the new page is animated into view. The framework will note the title of the incoming page to update the title when the new page is transitioned into view.

The simplest way to organize your jQuery Mobiel site or app is to have each "page" live within an individual HTML document and let the AJAX nav model take care of pulling pages in as needed. All pages in the jQuery Mobile demos work this way.

A single HTML document can contain multiple "pages" that are loaded together by stacking multiple divs, each with a data-role of "page". Each "page" block needs a unique id (id="foo") that will be used to link internally between "pages" (href="#foo"). When a link is clicked, the framework will look for an internal "page" with the id and transition it into view.

When linking from a single to a multi-page document, like the link below, you must add the data-ajax="false" attribute to the link to force a full page refresh.

Multipage example

By default, the framework applies a fade transition. To set a custom transition effect, add the data-transition attribute to the link.

none fade pop flip turn flow slide slidefade slideup slidedown

To set the transition default globally, bind to the mobileinit event and set the defaultPageTransition.

When the Back button is pressed, the framework will automatically apply the reverse version of the transition that was used to show the page. To specify that the reverse version of a transition should be used, add the data-direction="reverse" attribute to a link.

To give a standard page the appearance of a modal dialog, add the data-rel="dialog" attribute to the link. Transitions can also be set on dialog links.

Dialog: pop Dialog: flip

Links that point to other domains or that have rel="external", data-ajax="false" or target attributes will not be loaded with Ajax. Instead, these links will cause a full page refresh with no animated transition.

Both attributes (rel="external" and data-ajax="false") have the same effect, but a different semantic meaning: rel="external" should be used when linking to another site or domain, while data-ajax="false" is useful for simply opting a page within your domain from being loaded via Ajax. Because of security restrictions, the framework always opts links to external domains out of the Ajax behavior.

Non-AJAX link
External link

As of version 1.1, we added support for using data-ajax="false" on a parent container which allows you to exclude a large number of links from the Ajax navigation system. To activate this functionality, $.mobile.ignoreContentEnabled must be set to true. When building a jQuery Mobile application where the Ajax navigation system is disabled globally or frequently disabled on individual links, we recommend disabling the $.mobile.pushStateEnabled global configuration option to avoid inconsistent navigation behavior in some browsers.

When using single-page templates, you can prefetch pages into the DOM so that they're available instantly when the user visits them. To prefetch a page, add the data-prefetch attribute to a link that points to the page. jQuery Mobile then loads the target page in the background after the primary page has loaded and the pagecreate event has triggered.

This link will prefetch the page

Alternatively, you can prefetch a page programmatically using $.mobile.loadPage():

$.mobile.loadPage( pageUrl, { showLoadMsg: false } );

Keeping lots of pages in the DOM quickly fills the browser's memory, and can cause some mobile browsers to slow down or even crash. jQuery Mobile has a simple mechanism to keep the DOM tidy.

Whenever it loads a page via AJAX, it flags the page to be removed from the DOM when you navigate away from it later (technically, on the pagehide event). If you revisit a removed page, the browser may be able to retrieve the page's HTML file from its cache. If not, it re-fetches the file from the server. (In the case of nested listviews, jQuery Mobile removes all the pages that make up the nested list once you navigate to a page that's not part of the list.)

If you prefer, you can tell jQuery Mobile to keep previously-visited pages in the DOM instead of removing them. This lets you cache pages so that they're available instantly if the user returns to them.

$.mobile.page.prototype.options.domCache = true;

Alternatively, to cache just a particular page, you can add the data-dom-cache="true" attribute to the page's container.

To keep all previously-visited pages in the DOM, set the domCache option on the page plugin to true, like this:

pageContainerElement.page({ domCache: true });

Note that the contents of the first page isn't removed from the DOM, only pages loaded in via AJAX. Pages inside a multi-page template aren't affected by this feature at all - jQuery Mobile only removes pages loaded via Ajax.

By default all navigation within jQuery Mobile is based on changes and updates to location.hash. Whenever possible, page changes will use a smooth transition between the current "page" and the next, whether it is either already present in the DOM, or is automatically loaded via Ajax.

Hash values created by jQuery Mobile are normalized as full paths relative to the URL of the first "real" page that was loaded. The hash is always maintained as a valid URL, so any "page" in jQuery Mobile can be bookmarked or referenced in a link. To retrieve a non-hash-based URL, simply remove the # from the address and refresh the page.

In general, hash changes are created whenever a link is clicked in jQuery Mobile. When a link is clicked, jQuery Mobile will make sure that the link is referencing a local URL, and if so, it'll prevent the link's default click behavior from occurring and request the referenced URL via Ajax instead. When the page returns successfully, it will set the location.hash to the new page's relative URL.

Hash changes that occur independently of a click, such as when a user clicks the back button, are handled through the hashchange event, which is bound to the window object using Ben Alman's hashchange special event plugin (included in jQuery Mobile). When a hash change occurs (and also when the first page loads), the hashchange event handler will send the location.hash to the $.mobile.changePage() function, which in turn either loads or reveals the referenced page.

Once the referenced page is present in the DOM, the $.mobile.changePage() function applies a transition between the current active page and the new page. Page transitions happen through adding and removing classes that apply CSS animations. For example, in a slide-left transition, the exiting page is given the classes "slideleft" and "out", and the entering page is given the classes "slideleft" and "in", as well as a class of "ui-page-active" to mark it as the new "active" page being viewed. When the animation is complete, the "in" and "out" classes are removed, and the exited page loses its "ui-page-active" class.

There is an optional feature that converts the longer, hash-based URLs mentioned in the previous section into the full document path which is cleaner and makes the Ajax tracking transparent in the URL structure. This is built as an enhancement on top of the hash-based URL system for Ajax links. Note that despite the name, this feature technically converts hash-based URLs by using history.replaceState (not history.pushState) in the current release because this works more reliably across our target platforms. For browsers that do not support history.replaceState, or if this feature is disabled, hash-based URLs will be used instead.

Since the plugin initializes when the DOM is fully loaded you can enable and disable it manually by setting $.mobile.pushStateEnabled global configuration option to false anytime before document ready.

When building a jQuery Mobile application where the Ajax navigation is being explicitly disabled, either through the frequent use of rel="external" on links or by disabling Ajax navigation completely via the $.mobile.ajaxEnabled=false, we recommend disabling the pushState feature to fall back to the hash based navigation for more consistent behavior.

Within the framework, page changes - both for pages already in the DOM and for pages that need to be loaded via Ajax - use the $.mobile.changePage() function. $.mobile.changePage() contains all of the logic for finding pages to transition to and from, and how to handle various response conditions such as a page not found. $.mobile.changePage() can be called externally and accepts the following arguments: to, transition, back, changeHash. The to argument can accept either a string (such as a file URL or local element's id), an array (in which the first array item is any local page you'd like to transition from, and the second array item is the to page), or an object (with expected properties: URL, type ("get" or "post"), and data (for serialized parameters)), the latter of which is useful for loading pages that expect form data. The transition argument accepts a string representing a named transition, such as "slide". The back argument accepts a boolean representing whether the transition should go forward or in reverse. Lastly, the changeHash argument accepts a boolean for whether you'd like the URL to be updated upon a successful page change.

The $.mobile.changePage() function is used in a number of places in jQuery Mobile. For example, when a link is clicked, its href attribute is normalized and then $.mobile.changePage() handles the rest. When forms are submitted, jQuery Mobile simply gathers a few of the form's attributes, serializes its data, and once again, $.mobile.changePage() is used to handle the submission and response. Also, links that create dialogs use $.mobile.changePage()to open a referenced page without updating the hash, which is useful for keeping dialogs out of history tracking.

Another key ingredient to jQuery Mobile's page navigation model is the base element, which is injected into the head and modified on every page change to ensure that any assets (images, CSS, JS, etc.) referenced on that page will be requested from a proper path. In browsers that don't support dynamic updates to the base element (such as Firefox 3.6), jQuery Mobile loops through all of the referenced assets on the page and prefixes their href and src attributes with the base path.

Developer explanation of base URL management:

jQuery Mobile manages http requests using a combination of generated absolute URL paths and manipulating a generated <base> element's href attribute. The combination of these two approaches allows us to create URLs that contain full path information for loading pages, and a base element to properly direct asset requests made by those loaded pages (such as images and stylesheets).

The navigation model maintains a data-url attribute on all data-role="page" elements. This data-url attribute is used to track the origin of the page element. Pages embedded within the main application document all have their data-url parameter set to the id of their element with data-role="page". The only exception to this is the first-page in the document. The first-page is special because it can be addressed by its id if it has one, or by the document or base URL (with no hash fragment).

Pages that are external to the application document get pulled in dynamically via Ajax, and their data-url is set to the site relative path to the external page. If you are running in an environment where loading an external page from a different domain is allowed, then the data-url is set to the absolute URL.

Some plugins may choose to dynamically break a page's content into separate navigable pages, which can then be reached via deep links. One example of this would be the Listview plugin, which will break a nested UL (or OL) into separate pages, which are each given a data-url attribute so they can be linked to like any normal "page" in jQuery Mobile. However, in order to link to these pages, the page that generates them must first be requested from the server. To make this work, pages that are auto-generated by plugins use the following special data-url structure: <div data-url="page.html&subpageidentifier">

So, for example, a page generated by the listview plugin may have a data-url attribute like this: data-url="artists.html&ui-page=listview-1"

When a page is requested, jQuery Mobile knows to split the URL at "&ui-page" and make an HTTP request to the portion of the URL before that key. In the case of the listview example mentioned above, the URL would look like this: http://example.com/artists.html&ui-page=listview-1 ...and jQuery Mobile would request artists.html, which would then generate its sub-pages, creating the div with data-url="artists.html&ui-page=listview-1", which it will then display as the active page.

Note that the data-url attribute of the element contains the full URL path, not just the portion after &ui-page=. This allows jQuery Mobile to use a single consistent mechanism that matches URLs to page data-url attributes.

Under certain conditions, normal http requests will be used instead of Ajax requests. One case where this is true is when linking to pages on external websites. You can also specify that a normal http request be made through the following link attributes:

Form submissions

Form submissions are handled automatically through the navigation model as well. Visit the forms section for more information.

Application Cache

When using the application cache with jQuery Mobile there is at least one important issue to consider. Some browsers, when making requests to the cache will report an http status of 0 on success. This causes jQuery Core's $.ajax to trigger error handlers. The suggested workaround for users leveraging the application cache is to use a jQuery Ajax pre-filter. Something like the following (credit to jammus for the snippet):

$.ajaxPrefilter( function(options, originalOptions, jqXHR) {
	if ( applicationCache &&
		 applicationCache.status != applicationCache.UNCACHED &&
		 applicationCache.status != applicationCache.OBSOLETE ) {
		 // the important bit
		 options.isLocal = true;

Setting isLocal to true for your Ajax requests will alert jQuery Core that it should handle the 0 return values differently. Local requests exhibit similar behavior (ie 0 statuses), and Core will then fall back to determining success based on the presence of content in the xhr responseText attribute.

One important issue to note with the above is that it will set isLocal to true for all requests made via Ajax regardless of whether they are in the manifest or not so long as the cache is valid. This works for now because Core only consults the isLocal value when the status is in fact 0 which doesn't affect uncached results. There is no long term guarantee that isLocal will remain isolated in its purpose for handling 0 status values. If that changes it may break your application.

Known limitations

The non-standard environment created by jQuery Mobile's page navigation model introduces some conditions of which you should be aware when building pages: