Getting Started
Page Structure
jQuery Mobile uses data-role attributes to enhance HTML. A page is a div with data-role=page containing header, main, and footer sections. The viewport meta tag is essential for proper scaling on mobile devices. Load jQuery core before jquery.mobile.js.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css">
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
<div data-role="page" id="home">
<div data-role="header"><h1>Home</h1></div>
<div data-role="main" class="ui-content">Content</div>
<div data-role="footer"><h4>Footer</h4></div>
</div>
</body>
</html>Multiple Pages in One Document
You can place multiple data-role=page divs in a single HTML file. Link between them with anchor hrefs (#about). jQuery Mobile shows one page at a time and animates transitions. Only the first page in source order is shown on initial load.
<div data-role="page" id="home">
<div data-role="header"><h1>Home</h1></div>
<div data-role="main" class="ui-content">
<a href="#about" class="ui-btn">Go to About</a>
</div>
</div>
<div data-role="page" id="about" data-theme="b">
<div data-role="header"><h1>About</h1></div>
<div data-role="main" class="ui-content">
<a href="#home" class="ui-btn" data-direction="reverse">Back</a>
</div>
</div>AJAX Navigation & Links
By default, links to internal (#id) and same-origin pages are fetched via AJAX and swapped with a transition. Use data-ajax=false to force a normal full-page load (useful for non-jQuery Mobile pages). data-prefetch preloads the target so the transition is instant.
<!-- Default: links load via AJAX and animate a transition -->
<a href="detail.html" class="ui-btn">Open detail (AJAX)</a>
<!-- Force a full page reload (no AJAX) -->
<a href="external.html" data-ajax="false">Full reload</a>
<!-- Open in new window/tab -->
<a href="https://example.com" rel="external">External site</a>
<!-- Prefetch a page when this page loads -->
<a href="next.html" data-prefetch="true" class="ui-btn">Prefetch next</a>Prefetching & DOM Caching
Prefetching loads linked pages in the background so navigation feels instant. By default visited pages are removed from the DOM, but domCache keeps them for faster back-navigation at the cost of memory. Enable per-page with data-dom-cache or globally via the page prototype option.
<!-- Prefetch several pages -->
<a href="page1.html" data-prefetch="true">Page 1</a>
<a href="page2.html" data-prefetch="true">Page 2</a>
<!-- Globally enable DOM caching of visited pages -->
<script>
$(document).on("mobileinit", function () {
$.mobile.page.prototype.options.domCache = true;
});
</script>
<!-- Cache a single page -->
<div data-role="page" id="cached" data-dom-cache="true">...</div>Dialog Pages
Add data-rel=dialog to a link (or data-dialog=true on the page) to open a page styled as a modal dialog with a close button and transition. Use data-rel=back on a link to close it and return to the previous page.
<!-- Open a page as a dialog -->
<a href="#dialog" class="ui-btn" data-rel="dialog">Open dialog</a>
<div data-role="page" id="dialog" data-dialog="true">
<div data-role="header"><h1>Dialog</h1></div>
<div data-role="main" class="ui-content">
<p>This page is styled as a dialog.</p>
<a href="#" class="ui-btn" data-rel="back">Close</a>
</div>
</div>Global Configuration (mobileinit)
The mobileinit event fires after jQuery core loads but before jQuery Mobile initializes — bind your config here, before including jquery.mobile.js. Common overrides: default transitions, AJAX settings, and loading message text. Setting autoInitializePage=false lets you control when the first page initializes.
<script src="jquery-1.11.1.min.js"></script>
<script>
// Bind BEFORE loading jquery.mobile.js
$(document).on("mobileinit", function () {
$.mobile.defaultPageTransition = "slide";
$.mobile.defaultDialogTransition = "pop";
$.mobile.loadingMessage = "Loading...";
$.mobile.ajaxEnabled = true;
$.mobile.linkBindingEnabled = true;
$.mobile.autoInitializePage = true;
});
</script>
<script src="jquery.mobile-1.4.5.min.js"></script>Page Transitions
Basic Transitions
Add data-transition to a link to choose the animation when navigating. Transitions are CSS-based (hardware-accelerated where possible). 'none' skips animation for instant navigation. The same attribute works for dialogs and popups.
<!-- Apply a transition to a link -->
<a href="#page2" data-transition="slide">Slide</a>
<a href="#page2" data-transition="fade">Fade</a>
<a href="#page2" data-transition="pop">Pop</a>
<a href="#page2" data-transition="flip">Flip</a>
<a href="#page2" data-transition="none">None (instant)</a>Transition Types
jQuery Mobile ships with a set of 2D/3D CSS transitions. 3D transitions (turn, flow, flip) look great on capable devices but fall back gracefully on older hardware. pop and fade are the most performant and are recommended for dialogs and popups.
<!-- Available transitions in jQuery Mobile 1.4 -->
fade <!-- default, fade in/out -->
pop <!-- scale in from center (good for dialogs) -->
slide <!-- slide left to right -->
slideup <!-- slide up from bottom -->
slidedown <!-- slide down from top -->
slidfade <!-- slide + fade -->
turn <!-- 3D turn -->
flow <!-- 3D flow -->
flip <!-- 3D flip -->
none <!-- no animation -->Direction & Reverse
data-direction=reverse plays the transition backwards — typically used on Back buttons so the animation mirrors the forward navigation. This pairs with data-transition; if no transition is set, the default is reversed.
<!-- Reverse a transition (e.g., for Back buttons) -->
<a href="#home" data-transition="slide" data-direction="reverse">Back</a>
<!-- Globally reverse the default -->
<a href="#home" data-direction="reverse">Back (uses default transition reversed)</a>Dialog Transitions
Dialogs can use any transition, but pop and slidedown feel most natural for modals. Set a global default with $.mobile.defaultDialogTransition during mobileinit. The dialog's close action reverses the transition automatically.
<!-- Combine data-rel=dialog with a transition -->
<a href="#settings" data-rel="dialog" data-transition="pop">Settings</a>
<a href="#settings" data-rel="dialog" data-transition="slidedown">Settings (slide down)</a>
<!-- Set a global default dialog transition -->
<script>
$(document).on("mobileinit", function () {
$.mobile.defaultDialogTransition = "pop";
});
</script>Disabling & Fallback
Set data-transition=none or the global default to 'none' to disable animations — helpful on low-end devices or for accessibility. jQuery Mobile automatically detects 3D transform support and degrades 3D transitions (flip, turn, flow) to a simple fade when unsupported.
<!-- Disable transitions for a specific link -->
<a href="#page2" data-transition="none">No animation</a>
<!-- Globally disable (useful for older devices / testing) -->
<script>
$(document).on("mobileinit", function () {
$.mobile.defaultPageTransition = "none";
$.mobile.defaultDialogTransition = "none";
});
</script>
<!-- 3D transitions fall back to fade when not supported -->Toolbars (Header & Footer)
Fixed Header & Footer
Add data-position=fixed to keep a header or footer pinned at the top/bottom of the viewport while the page scrolls. Tapping the page toggles the toolbars' visibility by default. The page content gets padding so it isn't hidden behind the toolbars.
<div data-role="page" id="home">
<div data-role="header" data-position="fixed">
<h1>Fixed Header</h1>
</div>
<div data-role="main" class="ui-content">
<p>Scroll the page — the toolbars stay in place.</p>
</div>
<div data-role="footer" data-position="fixed">
<h4>Fixed Footer</h4>
</div>
</div>Fullscreen Toolbars
data-fullscreen=true overlays the fixed toolbars on top of the content (semi-transparent), instead of reserving space. Great for photo viewers or maps where content should fill the screen. The toolbars appear/disappear on tap just like fixed toolbars.
<div data-role="page" id="photo">
<div data-role="header" data-position="fixed" data-fullscreen="true">
<h1>Photos</h1>
</div>
<div data-role="main" class="ui-content">
<img src="photo.jpg" style="width:100%">
</div>
<div data-role="footer" data-position="fixed" data-fullscreen="true">
<h4>Footer over content</h4>
</div>
</div>Persistent Toolbars
When two pages have footers (or headers) with the same data-id and data-position=fixed, the toolbar persists across page transitions instead of animating with the page. This is the standard pattern for a persistent bottom navigation bar — only the active link changes per page.
<!-- Both pages use the SAME data-id so the footer persists -->
<div data-role="page" id="home">
<div data-role="footer" data-id="main-nav" data-position="fixed">
<div data-role="navbar">
<ul><li><a href="#home" class="ui-btn-active">Home</a></li>
<li><a href="#settings">Settings</a></li></ul>
</div>
</div>
</div>
<div data-role="page" id="settings">
<div data-role="footer" data-id="main-nav" data-position="fixed">
<div data-role="navbar">
<ul><li><a href="#home">Home</a></li>
<li><a href="#settings" class="ui-btn-active">Settings</a></li></ul>
</div>
</div>
</div>Tap Toggle Behavior
Fixed toolbars toggle visibility when the user taps the page. Set data-tap-toggle=false to keep a toolbar always visible. Related per-element options: data-hide-during-focus (hide when inputs are focused) and data-update-page-padding (re-apply page padding on resize).
<!-- Disable tap-to-toggle on a fixed toolbar -->
<div data-role="header" data-position="fixed" data-tap-toggle="false">
<h1>Always visible</h1>
</div>
<!-- Globally turn off tap toggle -->
<script>
$(document).on("mobileinit", function () {
$.mobile.toolbar.prototype.options.tapToggle = false;
});
</script>Toolbar Theme & Buttons
Headers can hold buttons positioned with the ui-btn-left / ui-btn-right classes. data-theme sets the color swatch of the bar. data-iconpos=notext shows only an icon for a compact look. Buttons inside a header are auto-styled as inline buttons.
<div data-role="header" data-theme="b">
<a href="#" class="ui-btn-left" data-icon="home" data-iconpos="notext">Home</a>
<h1>Title</h1>
<a href="#" class="ui-btn-right" data-icon="gear" data-iconpos="notext">Settings</a>
</div>Dynamically Updating Toolbars
After changing toolbar markup at runtime, call $(el).toolbar('refresh') to re-apply styling and padding. The toolbar widget (introduced in 1.4) manages fixed positioning and tap-toggle; initialize it manually with $().toolbar() if you add a toolbar after page create.
<script>
// Update the header title and re-enhance after DOM change
$(function () {
$("#my-header h1").text("New Title");
$("#my-header").toolbar("refresh");
});
</script>
<div data-role="header" id="my-header" data-position="fixed">
<h1>Old Title</h1>
</div>List Views
Basic Listview
Add data-role=listview to a <ul> to turn it into a touch-friendly list with full-width tappable rows. Each <li> containing an <a> becomes a linked row with a right arrow. data-inset=true insets the list with rounded corners and margins instead of edge-to-edge.
<ul data-role="listview" data-inset="true">
<li><a href="#">Apple</a></li>
<li><a href="#">Banana</a></li>
<li><a href="#">Cherry</a></li>
</ul>Inset Lists
Edge-to-edge lists span the full width (good for full-screen menus); inset lists have rounded corners and surrounding margins (good for content sections within a page). Use data-inset=true for inset lists, which look more like grouped settings panels.
<!-- Edge-to-edge (default) -->
<ul data-role="listview">
<li><a href="#">Item 1</a></li>
</ul>
<!-- Inset: rounded, with margins -->
<ul data-role="listview" data-inset="true">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
</ul>List Dividers
An <li> with data-role=list-divider becomes a non-clickable section header. data-autodividers=true automatically inserts dividers based on the first letter of each item's text — perfect for an alphabetical contact list.
<ul data-role="listview" data-inset="true">
<li data-role="list-divider">Fruits</li>
<li><a href="#">Apple</a></li>
<li><a href="#">Banana</a></li>
<li data-role="list-divider">Vegetables</li>
<li><a href="#">Carrot</a></li>
</ul>
<!-- Auto dividers from first letter -->
<ul data-role="listview" data-autodividers="true">
<li><a href="#">Alice</a></li>
<li><a href="#">Bob</a></li>
</ul>Count Bubbles & Thumbnails
Add a span with class=ui-li-count inside an <li> to show a numeric count bubble on the right. Use an <img> with class=ui-li-thumb (typically 80x80) for a left thumbnail. Combine with <h3>/<p> for rich, app-like list rows.
<ul data-role="listview" data-inset="true">
<!-- Count bubble -->
<li><a href="#">Inbox <span class="ui-li-count">12</span></a></li>
<!-- Thumbnail on the left -->
<li>
<a href="#">
<img src="thumb.jpg" class="ui-li-thumb">
<h3>Title</h3>
<p>Description</p>
<span class="ui-li-count">3</span>
</a>
</li>
</ul>Search Filter
data-filter=true adds a search input above the list that filters items by text in real time. data-filter-placeholder customizes the prompt. data-filter-reveal=true hides all items until the user types — useful for an autocomplete-style lookup.
<ul data-role="listview" data-filter="true"
data-filter-placeholder="Search fruits...">
<li><a href="#">Apple</a></li>
<li><a href="#">Banana</a></li>
<li><a href="#">Cherry</a></li>
</ul>
<!-- Filter reveals hidden items (collapsible search) -->
<ul data-role="listview" data-filter="true" data-filter-reveal="true">
<li><a href="#">Hidden until searched</a></li>
</ul>Split Buttons & Nested Lists
When an <li> contains two <a> elements, jQuery Mobile renders a split button: the main row navigates to the first link, and a separate icon button (set via data-split-icon) on the right opens the second. A nested <ul> inside an <li> becomes a drill-down sub-page automatically.
<!-- Split button: row link + icon link on the right -->
<ul data-role="listview" data-split-icon="gear" data-inset="true">
<li>
<a href="#detail">Go to detail</a>
<a href="#edit">Edit</a>
</li>
</ul>
<!-- Nested list (child <ul> becomes a sub-page) -->
<ul data-role="listview">
<li>Fruits
<ul>
<li><a href="#">Apple</a></li>
<li><a href="#">Banana</a></li>
</ul>
</li>
</ul>Form Controls
Form Structure & AJAX Submission
jQuery Mobile auto-enhances form inputs and submits forms via AJAX by default, showing a loading spinner and transitioning to the result page. Set data-ajax=false to do a traditional full-page submit (required for file uploads that don't use a modern API).
<form action="/submit" method="post" data-ajax="true">
<label for="name">Name:</label>
<input type="text" name="name" id="name" placeholder="Your name">
<button type="submit" class="ui-btn">Submit</button>
</form>
<!-- Disable AJAX for this form (normal full submit) -->
<form action="/upload" method="post" data-ajax="false">...</form>Text Inputs & Clear Button
All HTML5 input types (text, email, tel, number, password, date, etc.) are styled consistently. data-clear-btn=true adds an in-field clear (x) button. Use data-role=none to keep a control as a plain native input without jQuery Mobile styling.
<label for="email">Email</label>
<input type="email" id="email" data-clear-btn="true" placeholder="[email protected]">
<label for="phone">Phone</label>
<input type="tel" id="phone" data-clear-btn="true" data-clear-btn-text="Clear">
<!-- Non-enhanced native input -->
<input type="text" data-role="none">Field Containers
Wrap a label + control pair in a div with class=ui-field-contain. On wide screens the label and input sit side by side; on narrow phones they stack vertically. This responsive behavior replaces the older data-role=fieldcontain attribute.
<div class="ui-field-contain">
<label for="user">Username</label>
<input type="text" id="user">
</div>
<div class="ui-field-contain">
<label for="pwd">Password</label>
<input type="password" id="pwd">
</div>Search Input
An <input type=search> is enhanced into a search field with a magnifying-glass icon. Pair it with a listview by giving the input an id and setting data-input=#id on the listview's filter — this lets you place the search box anywhere on the page.
<label for="q">Search</label>
<input type="search" id="q" placeholder="Search...">
<!-- Search input feeding a listview filter -->
<input type="search" id="my-filter" data-type="search">
<ul data-role="listview" data-filter="true"
data-input="#my-filter">
<li><a href="#">Apple</a></li>
<li><a href="#">Banana</a></li>
</ul>Textarea & Hidden Inputs
Textareas are styled to match other inputs and auto-grow as you type by default; set data-autogrow=false to fix the height with a scrollbar instead. Hidden inputs are passed through untouched. Like all inputs, wrap them in ui-field-contain for responsive labels.
<label for="bio">Bio</label>
<textarea id="bio" placeholder="Tell us about you"></textarea>
<!-- Auto-grow textarea -->
<textarea id="bio" data-autogrow="false"></textarea>
<!-- Hidden inputs are not styled -->
<input type="hidden" name="id" value="42">Disabling Auto-enhancement
Add data-role=none to any control to skip jQuery Mobile enhancement and keep it native. For a project-wide rule, set keepNative during mobileinit to a selector string of elements that should never be enhanced — useful when mixing custom-styled controls with jQM pages.
<!-- Keep a control native (no jQM styling) -->
<select data-role="none">...</select>
<input type="checkbox" data-role="none">
<!-- Globally disable enhancement for a tag -->
<script>
$(document).on("mobileinit", function () {
$.mobile.page.prototype.options.keepNative = "select, input[type=checkbox]";
});
</script>Sliders
Basic Range Slider
An <input type=range> with min, max, value, and step is enhanced into a touch-friendly slider with a value bubble. The value attribute sets the initial position. The slider writes its value back to the input, so it submits normally with the form.
<label for="volume">Volume</label>
<input type="range" name="volume" id="volume"
value="50" min="0" max="100" step="1">Slider with Highlight
data-highlight=true fills the track to the left of the handle with the active theme color, giving a clear visual of the current level. Without it the track is a single flat color. Useful for settings like volume or brightness.
<label for="brightness">Brightness</label>
<input type="range" id="brightness"
value="70" min="0" max="100"
data-highlight="true">Mini Slider
data-mini=true renders a smaller, more compact slider that takes less vertical space — handy when grouping several controls in a settings panel. It behaves identically to the regular slider, just at a reduced size.
<label for="age">Age</label>
<input type="range" id="age" value="25" min="0" max="120"
data-mini="true" data-highlight="true">Step & Multiple Sliders
step controls the increment (e.g., step=5 snaps to 0, 5, 10, ...). Each range input is an independent slider; for a dual-handle range you must build a custom widget or use a third-party plugin. The native value, min, max attributes drive the behavior.
<label for="temp">Temperature (step 5)</label>
<input type="range" id="temp" value="20" min="0" max="100" step="5">
<!-- Two independent sliders -->
<label for="low">Min</label>
<input type="range" id="low" value="10" min="0" max="100">
<label for="high">Max</label>
<input type="range" id="high" value="90" min="0" max="100">Slider Events
The slider emits slidestart when the user begins dragging the handle and slidestop when the drag ends. For continuous updates during the drag, bind to the native 'input' or 'change' event on the underlying range input. Read/write the value with $(el).val().
<label for="vol">Volume</label>
<input type="range" id="vol" value="50" min="0" max="100">
<script>
$("#vol").on("slidestart", function () {
console.log("User started dragging");
});
$("#vol").on("slidestop", function () {
console.log("Value is now " + $(this).val());
});
</script>Flip Toggle Switches
Basic Flip Toggle
A flip switch is a <select> with exactly two <option> elements and data-role=slider. It renders as an iOS-style on/off toggle. The selected option determines the initial state, and the value submits like a normal select (the value of the chosen option).
<label for="notify">Notifications</label>
<select name="notify" id="notify" data-role="slider">
<option value="off">Off</option>
<option value="on" selected>On</option>
</select>Custom Labels
The text of the two options becomes the labels on each side of the switch. You can use any short text (On/Off, Yes/No, Enabled/Disabled). Keep labels short so they fit within the toggle without truncation on small screens.
<label for="wifi">Wi-Fi</label>
<select id="wifi" data-role="slider">
<option value="disabled">Disabled</option>
<option value="enabled" selected>Enabled</option>
</select>Mini Flip Switch
data-mini=true renders a smaller flip switch that takes less vertical space, matching mini sliders and other mini controls. Pair mini controls together in dense settings panels for a consistent compact look.
<label for="sync">Auto-sync</label>
<select id="sync" data-role="slider" data-mini="true">
<option value="no">No</option>
<option value="yes" selected>Yes</option>
</select>Flip Theme
data-theme sets the color of the switch handle, and data-track-theme sets the color of the track behind it. Mixing swatches (e.g., a dark handle on a light track) makes the active state more visually distinct.
<label for="darkmode">Dark mode</label>
<select id="darkmode" data-role="slider"
data-theme="b" data-track-theme="a">
<option value="off">Off</option>
<option value="on" selected>On</option>
</select>Programmatic Toggle
Set the value with $(el).val(value) then call .slider('refresh') to update the visual toggle to match. Read the current state with .val(). Always refresh after changing the underlying select's value programmatically, or the handle won't move.
<select id="power" data-role="slider">
<option value="off">Off</option>
<option value="on">On</option>
</select>
<script>
// Turn the switch on programmatically
$("#power").val("on").slider("refresh");
// Read current state
var state = $("#power").val(); // "on" or "off"
</script>Checkboxes & Radios
Checkboxes
A checkbox is a normal <input type=checkbox> wrapped by (or adjacent to) a <label for=id>. jQuery Mobile styles the label as a tappable block. When the label wraps the input, the for attribute is optional. Checked state submits as usual with the form.
<label for="agree"><input type="checkbox" id="agree" name="agree"> I agree</label>
<label for="news"><input type="checkbox" id="news" name="news" checked> Newsletter</label>
<!-- Wrap in ui-field-contain for layout -->
<div class="ui-field-contain">
<label for="agree">I agree to terms</label>
<input type="checkbox" id="agree">
</div>Radio Buttons
Group radios by giving them the same name attribute. Wrap the group in a fieldset with data-role=controlgroup (and a <legend>) to cluster them visually with shared corners. Only one radio in a same-named group can be checked at a time.
<fieldset data-role="controlgroup">
<legend>Choose a color:</legend>
<label for="r"><input type="radio" name="color" id="r" value="red" checked> Red</label>
<label for="g"><input type="radio" name="color" id="g" value="green"> Green</label>
<label for="b"><input type="radio" name="color" id="b" value="blue"> Blue</label>
</fieldset>Horizontal Controlgroups
data-type=horizontal lays out the checkboxes or radios in a single row as a segmented control instead of a vertical stack. This is compact and works well for short labels (S/M/L, Yes/No). Keep labels short so they fit on narrow screens.
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Size:</legend>
<label for="s"><input type="radio" name="size" id="s" value="s" checked> S</label>
<label for="m"><input type="radio" name="size" id="m" value="m"> M</label>
<label for="l"><input type="radio" name="size" id="l" value="l"> L</label>
</fieldset>Mini & Theme
data-mini=true shrinks the controls, and data-theme sets the swatch applied when an item is checked/active. Theme the active state to stand out from the page background. These options apply to the whole controlgroup at once.
<fieldset data-role="controlgroup" data-mini="true" data-theme="b">
<label for="a"><input type="checkbox" id="a"> Option A</label>
<label for="b"><input type="checkbox" id="b"> Option B</label>
</fieldset>Refresh After Change
After setting a checkbox/radio's checked property in code, call .checkboxradio('refresh') so the enhanced visual matches. If you add or remove inputs inside a controlgroup at runtime, call .controlgroup('refresh') to re-apply the grouped styling.
<input type="checkbox" id="c1">
<script>
// Check programmatically and update the visual state
$("#c1").prop("checked", true).checkboxradio("refresh");
// For a controlgroup, refresh the group after adding/removing items
$("#grp").controlgroup("refresh");
</script>Popups
Basic Popup
A popup is a div with data-role=popup. Open it by linking to its id with data-rel=popup. The popup overlays the page centered by default. Add ui-content for padding, and use data-rel=back on a link inside to close it.
<a href="#myPopup" data-rel="popup" class="ui-btn">Open popup</a>
<div data-role="popup" id="myPopup" class="ui-content">
<p>This is a popup.</p>
<a href="#" class="ui-btn" data-rel="back">Close</a>
</div>Popup Transitions
Use data-transition on the opening link (or on the popup itself) to choose the animation. pop and fade are the most natural for popups. The same transition set used for pages applies here; the close action reverses the transition automatically.
<a href="#p" data-rel="popup" data-transition="pop">Pop</a>
<a href="#p" data-rel="popup" data-transition="fade">Fade</a>
<a href="#p" data-rel="popup" data-transition="slidedown">Slide down</a>
<div data-role="popup" id="p" class="ui-content" data-theme="a">
<p>Transitioned in.</p>
</div>Popup Positioning
data-position-to controls where the popup appears: 'origin' (the element that opened it, default), '#someId' (a specific element), or 'window' (centered on screen). You can also pass x/y coordinates when opening programmatically with popup('open', x, y).
<!-- Position relative to an element / coordinates -->
<a href="#tip" data-rel="popup" data-position-to="origin">Tip (on the link)</a>
<a href="#tip" data-rel="popup" data-position-to="#target">Tip (on #target)</a>
<a href="#tip" data-rel="popup" data-position-to="window">Centered</a>
<div data-role="popup" id="tip" class="ui-content">
<p>Positioned popup.</p>
</div>Popup Menu & Tooltip
A popup can contain any content — a listview becomes a context menu, a paragraph becomes a tooltip. Style the popup with data-theme and the inner content with its own theme. Popups close automatically when the user taps outside (unless data-dismissible=false).
<a href="#menu" data-rel="popup" class="ui-btn">Menu</a>
<div data-role="popup" id="menu" data-theme="b">
<ul data-role="listview" data-inset="true" data-theme="d">
<li data-role="divider">Actions</li>
<li><a href="#">Edit</a></li>
<li><a href="#">Share</a></li>
<li><a href="#">Delete</a></li>
</ul>
</div>Dialog Popup
A popup positioned at the window center with a close button acts as a modal dialog. Add an X button (ui-icon-delete with ui-btn-icon-notext) in the corner. Constrain the width with a max-width style for a true dialog look instead of a full-width sheet.
<a href="#dlg" data-rel="popup" data-position-to="window"
data-transition="pop" class="ui-btn">Open dialog</a>
<div data-role="popup" id="dlg" data-theme="a" class="ui-content"
style="max-width:400px;">
<a href="#" data-rel="back" class="ui-btn ui-corner-all ui-icon-delete
ui-btn-icon-notext ui-btn-right">Close</a>
<h3>Confirm</h3>
<p>Are you sure?</p>
<a href="#" class="ui-btn ui-btn-b" data-rel="back">Yes</a>
<a href="#" class="ui-btn" data-rel="back">No</a>
</div>Programmatic Open & Dismissible
Open or close a popup from code with .popup('open'/'close'). data-dismissible=false prevents closing by tapping outside, forcing the user to use a Close button — ideal for required confirmations. You can pass x/y coordinates or a position object when opening.
<div data-role="popup" id="p2" data-dismissible="false">
<p>Cannot close by tapping outside.</p>
<a href="#" class="ui-btn" data-rel="back">Close</a>
</div>
<script>
// Open programmatically (optionally at coordinates)
$("#p2").popup("open");
$("#p2").popup("open", { x: 100, y: 200 });
// Close programmatically
$("#p2").popup("close");
</script>Panels
Basic Panel
A panel is a div with data-role=panel, placed inside a page (usually before the header). Open it by linking to its id with a button. Use data-rel=close on a link inside to close the panel. Panels are perfect for slide-out navigation menus.
<div data-role="page" id="home">
<div data-role="panel" id="myPanel">
<h2>Menu</h2>
<p>Panel content here.</p>
<a href="#" class="ui-btn" data-rel="close">Close</a>
</div>
<div data-role="header">
<a href="#myPanel" class="ui-btn ui-btn-inline ui-corner-all ui-icon-bars ui-btn-icon-notext">Menu</a>
<h1>Home</h1>
</div>
<div data-role="main" class="ui-content">
<p>Page content.</p>
</div>
</div>Panel Display Modes
data-display controls the open animation: 'reveal' (default) slides the page away to uncover the panel beneath; 'overlay' slides the panel on top of the page; 'push' moves both the panel in and the page over. Overlay is most common for menus.
<div data-role="panel" id="p1" data-display="reveal">Reveal</div>
<div data-role="panel" id="p2" data-display="overlay">Overlay</div>
<div data-role="panel" id="p3" data-display="push">Push</div>
<!-- data-display controls how the panel interacts with the page:
reveal : panel sits under the page, page slides away
overlay: panel slides over the page (page stays)
push : both panel and page slide -->Panel Position
data-position=left (default) or right sets which side the panel slides in from. You can have both a left and a right panel in the same page. Only one panel can be open at a time; opening a second closes the first.
<!-- Left panel (default) -->
<div data-role="panel" id="leftP" data-position="left">Left</div>
<!-- Right panel -->
<div data-role="panel" id="rightP" data-position="right">Right</div>
<a href="#leftP" class="ui-btn">Open left</a>
<a href="#rightP" class="ui-btn">Open right</a>Dismissible & Swipe
data-dismissible=true (default) closes the panel when the user taps outside it. data-swipe-close=true lets the user swipe in the opposite direction to close it (e.g., swipe right closes a left panel). Both are on by default for overlay panels.
<div data-role="panel" id="p"
data-dismissible="true"
data-swipe-close="true"
data-position="left"
data-display="overlay">
<p>Tap outside or swipe to close.</p>
</div>Panel Events
Panels fire panelbeforeopen, panelopen, panelbeforeclose, and panelclose events. Returning false from a 'before' handler cancels the action — useful to confirm before closing. Open/close from code with .panel('open'/'close').
<div data-role="panel" id="p">...</div>
<script>
$("#p").on("panelopen", function () {
console.log("Panel opened");
});
$("#p").on("panelbeforeclose", function () {
// return false here to prevent closing
console.log("About to close");
});
$("#p").on("panelclose", function () {
console.log("Panel closed");
});
// Open / close programmatically
$("#p").panel("open");
$("#p").panel("close");
</script>Collapsibles
Basic Collapsible
A div with data-role=collapsible wraps a heading (h1-h6) as the clickable header and the rest as expandable content. It starts collapsed by default. Clicking the header toggles the content open and closed with a +/- icon.
<div data-role="collapsible">
<h3>Section title</h3>
<p>Hidden content shown when expanded.</p>
<p>Click the header to toggle.</p>
</div>Collapsible Icons & Theme
Customize the indicator with data-collapsed-icon and data-expanded-icon (default plus/minus). data-theme styles the header; data-content-theme styles the expanded content area. data-collapsed=false makes the section start expanded instead of collapsed.
<div data-role="collapsible"
data-collapsed-icon="carat-r"
data-expanded-icon="carat-d"
data-theme="b" data-content-theme="a"
data-collapsed="false">
<h3>Initially open</h3>
<p>Custom icons and theme.</p>
</div>Collapsible Set (Accordion)
A collapsibleset groups collapsibles so only one is open at a time — an accordion. Opening one automatically closes the others. (In 1.4 the attribute is data-role=collapsibleset; the older collapsible-set name still works.) The whole set shares a unified theme.
<div data-role="collapsibleset" data-theme="a" data-content-theme="a">
<div data-role="collapsible">
<h3>Section 1</h3>
<p>Only one section open at a time.</p>
</div>
<div data-role="collapsible" data-collapsed="false">
<h3>Section 2 (open by default)</h3>
<p>Opening this closes Section 1.</p>
</div>
<div data-role="collapsible">
<h3>Section 3</h3>
<p>Third section.</p>
</div>
</div>Pre-expanded & Inset
In a collapsibleset, set data-collapsed=false on the section you want open initially. data-inset=true (default for sets) gives the group rounded corners and margins. Edge-to-edge sets use data-inset=false to span full width.
<!-- A set always starts with one open by default; control with data-collapsed -->
<div data-role="collapsibleset" data-inset="true">
<div data-role="collapsible" data-collapsed="false">
<h3>Open first</h3>
<p>Content</p>
</div>
<div data-role="collapsible">
<h3>Closed second</h3>
<p>Content</p>
</div>
</div>Collapsible with Listview
A collapsible can contain any widget, including a listview. This is a great pattern for grouping a long list under a collapsible header. Add data-filter=true to the collapsible to filter the inner listview's items via a search box inside the header area.
<div data-role="collapsible" data-filter="true">
<h3>Contacts</h3>
<ul data-role="listview">
<li><a href="#">Alice</a></li>
<li><a href="#">Bob</a></li>
<li><a href="#">Carol</a></li>
</ul>
</div>Programmatic Expand/Collapse
Control a collapsible from code with .collapsible('expand') and .collapsible('collapse'). Listen to the 'collapse' and 'expand' events to react to user toggling. For a set, expanding one section programmatically collapses the others automatically.
<div data-role="collapsible" id="c">
<h3>Section</h3>
<p>Content</p>
</div>
<script>
// Expand or collapse from code
$("#c").collapsible("expand");
$("#c").collapsible("collapse");
// Toggle based on current state
$("#c h3").click(); // simplest manual toggle
</script>Tabs
Basic Tabs
A tabs widget is a div with data-role=tabs containing a navbar (the tab links) and content panels whose ids match the link hrefs. The link with ui-btn-active is shown first. Clicking a tab shows its panel and hides the others — no page transition.
<div data-role="tabs" id="myTabs">
<div data-role="navbar">
<ul>
<li><a href="#tab1" class="ui-btn-active">One</a></li>
<li><a href="#tab2">Two</a></li>
<li><a href="#tab3">Three</a></li>
</ul>
</div>
<div id="tab1" class="ui-body-d ui-content">Content 1</div>
<div id="tab2" class="ui-body-d ui-content">Content 2</div>
<div id="tab3" class="ui-body-d ui-content">Content 3</div>
</div>Tabs with Icons
Add ui-icon-{name} and ui-btn-icon-top classes to the tab links to show icons above the labels, giving an app-like tab bar. The active tab keeps ui-btn-active. Use ui-btn-icon-top so the icon sits above the text in the tab strip.
<div data-role="tabs">
<div data-role="navbar">
<ul>
<li><a href="#t1" class="ui-btn-active ui-icon-home ui-btn-icon-top">Home</a></li>
<li><a href="#t2" class="ui-icon-search ui-btn-icon-top">Search</a></li>
<li><a href="#t3" class="ui-icon-gear ui-btn-icon-top">Settings</a></li>
</ul>
</div>
<div id="t1" class="ui-content">Home tab</div>
<div id="t2" class="ui-content">Search tab</div>
<div id="t3" class="ui-content">Settings tab</div>
</div>AJAX Tabs
When a tab link's href is a URL (not #id), the tabs widget loads that page via AJAX into the container on activation. The first tab is loaded automatically when the page initializes. This is useful for lazily loading heavy content per tab.
<div data-role="tabs">
<div data-role="navbar">
<ul>
<li><a href="ajax-tab1.html" class="ui-btn-active">One</a></li>
<li><a href="ajax-tab2.html">Two</a></li>
</ul>
</div>
<!-- The first tab's content is loaded into this container -->
<div class="ui-content" id="ajax-content"></div>
</div>Tabs Persistence
Tabs don't remember their active state across reloads by default. Use the tabsactivate event (which gives ui.newPanel/ui.oldPanel) plus localStorage to persist the selection. Re-trigger the saved tab's click on load to restore it.
<div data-role="tabs" id="t">
<div data-role="navbar">
<ul>
<li><a href="#a" class="ui-btn-active">A</a></li>
<li><a href="#b">B</a></li>
</ul>
</div>
<div id="a" class="ui-content">A</div>
<div id="b" class="ui-content">B</div>
</div>
<script>
// Remember the active tab across reloads
var saved = localStorage.getItem("activeTab") || "#a";
$("#t a[href='" + saved + "']").click();
$("#t").on("tabsactivate", function (e, ui) {
localStorage.setItem("activeTab", "#" + ui.newPanel.attr("id"));
});
</script>Tab Events
tabsbeforeactivate fires before a tab switch (return false to cancel); tabsactivate fires after. Both give ui.newTab/ui.oldTab (the <a> links) and ui.newPanel/ui.oldPanel (the content divs). Use them to lazy-load content, log analytics, or validate before switching.
<div data-role="tabs" id="t">...</div>
<script>
$("#t").on("tabsbeforeactivate", function (e, ui) {
// ui.newTab, ui.oldTab, ui.newPanel, ui.oldPanel
// return false to cancel the switch
console.log("Switching to", ui.newPanel.attr("id"));
});
$("#t").on("tabsactivate", function (e, ui) {
console.log("Now showing", ui.newPanel.attr("id"));
});
</script>Theming
Theme Swatches (a-e)
jQuery Mobile theming uses lettered 'swatches' (a-e) rather than one color. a is the highest-contrast (dark) and is the default for headers/footers; b is a blue accent; c is the default light page background. Apply a swatch with data-theme on any element.
<!-- jQuery Mobile ships with 5 swatches: a, b, c, d, e -->
<!-- a = black (high contrast), b = blue, c = light gray,
d = medium gray, e = yellow -->
<div data-role="page" data-theme="b">
<div data-role="header" data-theme="a"><h1>Dark header</h1></div>
<div data-role="main" class="ui-content">Page body</div>
<div data-role="footer" data-theme="a"><h4>Dark footer</h4></div>
</div>Applying Themes
For buttons use the ui-btn-{swatch} class (e.g., ui-btn-b for a blue button). For other elements use data-theme={swatch}. A child inherits its parent's swatch unless you set one explicitly. The default page swatch is 'c' (light gray).
<!-- Per element -->
<a href="#" class="ui-btn ui-btn-a">Swatch A button</a>
<a href="#" class="ui-btn ui-btn-b">Swatch B button</a>
<!-- On bars, lists, forms -->
<div data-role="header" data-theme="b">...</div>
<ul data-role="listview" data-theme="c">...</ul>
<input type="text" data-theme="b">Overlay Theme
data-overlay-theme sets the color of the dimmed backdrop behind a popup, dialog, or custom select menu. Use a dark swatch (a or b) for the overlay so the foreground content stands out. The popup's own data-theme controls the popup box color.
<!-- Overlay theme for popups, dialogs, custom selects -->
<div data-role="popup" id="p" data-overlay-theme="b" data-theme="a"
class="ui-content">
<p>Dark backdrop, light popup.</p>
</div>
<a href="#p" data-rel="popup" data-transition="pop" class="ui-btn">Open</a>List & Button Themes
Listviews accept separate themes: data-theme for rows, data-divider-theme for the divider headers, and data-count-theme for the count bubbles. This lets you highlight dividers while keeping rows subtle. The same fine-grained theming applies to buttons and forms.
<ul data-role="listview" data-theme="d" data-divider-theme="b"
data-count-theme="b" data-inset="true">
<li data-role="list-divider">Group (swatch b)</li>
<li><a href="#">Item (swatch d) <span class="ui-li-count">5</span></a></li>
</ul>Custom Swatches
Each swatch is just a set of CSS classes (.ui-bar-{x}, .ui-body-{x}, .ui-btn-up-{x}, etc.). To add a custom swatch 'f', copy these rules and recolor them — or use the ThemeRoller tool to generate a complete custom theme file. Then reference it with data-theme=f.
/* Add a custom swatch 'f' by copying the .ui-bar-f, .ui-body-f,
.ui-btn-up-f, .ui-btn-hover-f, .ui-btn-down-f rules and changing
the colors. ThemeRoller generates these for you. */
.ui-bar-f { background: #6c2; color: #fff; }
.ui-body-f { background: #efe; color: #030; }
.ui-btn-up-f { background: #6c2; color: #fff; }
.ui-btn-hover-f { background: #5b1; color: #fff; }
<!-- Use it like any built-in swatch -->
<div data-role="header" data-theme="f"><h1>Green header</h1></div>Theme Inheritance
Elements inherit the nearest ancestor's swatch when they don't set their own. Set a swatch high up (e.g., on the page) to theme everything inside consistently, then override individual elements as needed. Change the global default page theme during mobileinit.
<div data-role="page" data-theme="b">
<!-- Inherits swatch b unless overridden -->
<div data-role="main" class="ui-content">
<a href="#" class="ui-btn">Inherits b</a>
<a href="#" class="ui-btn ui-btn-a">Explicit a</a>
<a href="#" class="ui-btn" data-theme="a">Explicit a (attr)</a>
</div>
</div>
<!-- Global default swatch -->
<script>
$(document).on("mobileinit", function () {
$.mobile.page.prototype.options.theme = "b";
});
</script>Responsive Layout
Grid Layout
Grids are CSS classes, not widgets. ui-grid-a makes a 2-column grid, ui-grid-b is 3 columns, up to ui-grid-d (5 columns). Children get ui-block-a, ui-block-b, ... in order and wrap automatically. Grids are always 100% wide and don't respond to breakpoints on their own.
<!-- 2-column grid (ui-grid-a) -->
<div class="ui-grid-a">
<div class="ui-block-a"><div class="ui-bar">A</div></div>
<div class="ui-block-b"><div class="ui-bar">B</div></div>
</div>
<!-- 3-column grid (ui-grid-b), 4 = ui-grid-c, 5 = ui-grid-d -->
<div class="ui-grid-b">
<div class="ui-block-a">A</div>
<div class="ui-block-b">B</div>
<div class="ui-block-c">C</div>
</div>Responsive Grids
jQuery Mobile grids don't have built-in breakpoints, but you can add a custom media query: at narrow widths set the blocks to width:100% and float:none so they stack vertically, and on wider screens let the default columns apply. Add a marker class to scope the rule.
<style>
/* Stack grid columns on phones, side-by-side on tablets */
@media (max-width: 40em) {
.ui-responsive .ui-block-a,
.ui-responsive .ui-block-b { width: 100%; float: none; }
}
</style>
<div class="ui-grid-a ui-responsive">
<div class="ui-block-a">Left (stacks on phone)</div>
<div class="ui-block-b">Right (stacks on phone)</div>
</div>Reflow Table
A reflow table (data-mode=reflow) reorganizes into a stacked card layout on narrow screens, repeating each column's header as a label next to its value. Add the ui-responsive class so the reflow only kicks in below the breakpoint, keeping a normal table on wide screens.
<table data-role="table" data-mode="reflow" class="ui-responsive">
<thead><tr><th>Name</th><th>Age</th><th>City</th></tr></thead>
<tbody>
<tr><td>Alice</td><td>30</td><td>NYC</td></tr>
<tr><td>Bob</td><td>25</td><td>LA</td></tr>
</tbody>
</table>
<!-- On narrow screens each cell shows its column header as a label -->Column Toggle Table
A columntoggle table adds a 'Columns...' button that lets users choose which columns to show. Assign data-priority=1..6 to optional columns (lower = more important, shown at wider breakpoints); columns without a priority always show. The most important columns remain on phones; the rest are tucked into the menu.
<table data-role="table" data-mode="columntoggle"
class="ui-responsive" id="tbl">
<thead>
<tr>
<th data-priority="1">Rank</th>
<th data-priority="2">Name</th>
<th>Team</th> <!-- priority 'persist' (always shown) -->
<th data-priority="3">Points</th>
<th data-priority="4">Wins</th>
</tr>
</thead>
<tbody><tr><td>1</td><td>Alice</td><td>Red</td><td>100</td><td>10</td></tr></tbody>
</table>Breakpoints & Helper Classes
jQuery Mobile has no utility breakpoint classes; you write your own media queries for custom layouts. The built-in 40em (640px) breakpoint only governs when responsive tables (ui-responsive) switch between stacked and tabular modes. For grids and panels, define your own breakpoints with em-based queries.
<!-- jQuery Mobile doesn't ship breakpoint classes like Bootstrap,
but you can combine media queries with jQM structure. -->
<style>
@media (min-width: 45em) { /* tablet+ */
.split { width: 50%; float: left; box-sizing: border-box; padding: 0 .5em; }
}
</style>
<div class="split">Left panel</div>
<div class="split">Right panel</div>
<!-- ui-responsive class triggers table breakpoints at 40em (640px) -->Touch Events
Tap & Taphold
tap fires on a quick touch (faster and more reliable than click on mobile, which waits ~300ms). taphold fires when the user holds their finger down for ~750ms. Both are normalized to work with mouse and touch, so the same code runs on desktop and mobile.
<div id="box" class="ui-bar">Tap or hold me</div>
<script>
$("#box").on("tap", function () {
$(this).css("background", "yellow");
});
$("#box").on("taphold", function () {
$(this).css("background", "red");
});
</script>Swipe & Swipe Direction
swipe fires on any horizontal swipe; swipeleft and swiperight tell you the direction — handy for image carousels or page navigation. These are based on horizontal movement; vertical scrolling is intentionally not treated as a swipe so normal page scrolling still works.
<div id="card" class="ui-bar">Swipe me</div>
<script>
$("#card").on("swipe", function () {
console.log("Swiped in any direction");
});
$("#card").on("swipeleft", function () {
$(this).text("Swiped left -> next");
});
$("#card").on("swiperight", function () {
$(this).text("Swiped right -> prev");
});
</script>Swipe Thresholds
A swipe only registers if it covers at least horizontalDistanceThreshold (default 30px) within durationThreshold (default 1000ms), and stays under verticalDistanceThreshold vertically. Raise the horizontal threshold to require longer swipes; lower it for a more sensitive feel. Set these during mobileinit.
<script>
// Globally tune swipe sensitivity (bind before jQM loads)
$(document).on("mobileinit", function () {
$.event.special.swipe.horizontalDistanceThreshold = 60; // px, default 30
$.event.special.swipe.durationThreshold = 800; // ms, default 1000
$.event.special.swipe.verticalDistanceThreshold = 40; // px, default 75
});
</script>
<script src="jquery.mobile-1.4.5.min.js"></script>Virtual Mouse Events
vmouse* events are jQuery Mobile's unified mouse/touch/pointer events — they fire consistently whether the user uses a finger or a mouse. Use vclick instead of click to avoid the mobile 300ms delay. They're the building blocks that tap and swipe are built on.
<script>
// vmouse events unify mouse + touch + pointer
$("#el").on("vmousedown", function () { /* finger down / mouse down */ });
$("#el").on("vmouseup", function () { /* finger up / mouse up */ });
$("#el").on("vmousemove", function () { /* drag */ });
$("#el").on("vmouseover", function () { /* hover-in (best-effort) */ });
$("#el").on("vmouseout", function () { /* hover-out (best-effort) */ });
$("#el").on("vclick", function () { /* tap/click unified */ });
</script>Orientation Change
orientationchange fires when the device rotates, with e.orientation equal to 'portrait' or 'landscape'. Wrap layout-dependent code in a short setTimeout because the viewport dimensions update slightly after the event fires. Listen to the 'resize' event as a fallback on devices without a gyroscope.
<script>
$(window).on("orientationchange", function (e) {
// e.orientation is "portrait" or "landscape"
console.log("Now " + e.orientation);
});
// React after the rotation finishes (layout is settled)
$(window).on("orientationchange", function (e) {
setTimeout(function () {
$("body").removeClass("portrait landscape").addClass(e.orientation);
}, 300);
});
</script>Scroll & Throttling
scrollstart and scrollstop are jQuery Mobile's throttled scroll events (the browser throttles scroll handlers natively, but these give clear start/stop moments). To prevent scrolling/zooming on an element — e.g., a drawing canvas or a map — bind touchmove and return false.
<script>
// scrollstart / scrollstop are throttled for performance
$(document).on("scrollstart", function () {
$("#hint").hide();
});
$(document).on("scrollstop", function () {
$("#hint").show();
});
// Silence touch scroll on a specific element
$("#canvas").on("touchmove", false);
</script>Page Events & Lifecycle
Page Initialization Events
pagebeforecreate fires before jQuery Mobile enhances the page's markup — the best place to inject classes or widgets so they get enhanced too. pagecreate fires right after enhancement completes — use it to bind event handlers and initialize plugins. Each fires once per page.
<div data-role="page" id="home">
<div data-role="main" class="ui-content">
<a href="#second" class="ui-btn">Go to second</a>
</div>
</div>
<script>
$(document).on("pagebeforecreate", "#home", function () {
// Before enhancement — good place to add classes/widgets
});
$(document).on("pagecreate", "#home", function () {
// After enhancement, before show — bind widgets here
console.log("Home page created");
});
</script>Page Show & Hide
pagebeforeshow/pageshow fire before/after a page becomes visible; pagebeforehide/pagehide fire before/after it's hidden. 'show' events fire every time the page is displayed (not just once), so they're the right place to refresh dynamic data when returning to a page.
<script>
$(document).on("pagebeforeshow", "#home", function () {
console.log("About to show home");
});
$(document).on("pageshow", "#home", function () {
console.log("Home shown (transition done)");
});
$(document).on("pagebeforehide", "#home", function () {
console.log("About to leave home");
});
$(document).on("pagehide", "#home", function () {
console.log("Home hidden");
});
</script>Page Before Change
pagebeforechange fires before any navigation and is the place to intercept or redirect it (call preventDefault to cancel). pagechange fires after a successful navigation; pagechangefailed fires if loading the target page errored. These fire for both internal (#id) and AJAX navigations.
<script>
$(document).on("pagebeforechange", function (e, data) {
// data.toPage is the target (URL string or jQuery object)
// data.options has transition, reverse, etc.
// return false (or e.preventDefault()) to cancel navigation
if (typeof data.toPage === "string" && data.toPage.indexOf("block") > -1) {
e.preventDefault();
alert("Blocked");
}
});
$(document).on("pagechange", function (e, data) {
console.log("Navigation completed");
});
$(document).on("pagechangefailed", function (e, data) {
console.log("Navigation failed");
});
</script>Page Container Load
pageload fires when an AJAX-fetched page is successfully inserted into the DOM (data.url and data.page are provided). pageloadfailed fires on a load error — by default jQM shows an error message; returning false from a handler tells jQM you've handled it yourself.
<script>
// Fires when a page is loaded via AJAX into the DOM
$(document).on("pageload", function (e, data) {
console.log("Loaded: " + data.url);
console.log("Page obj:", data.page);
});
$(document).on("pageloadfailed", function (e, data) {
// return false to let jQM show its default error message
console.log("Failed to load: " + data.url);
});
</script>Binding to Page Events
Bind page events with event delegation on document, filtering by the page's #id selector — this works even for pages pulled in later via AJAX. For programmatic navigation use the pagecontainer widget's 'change' method (the modern replacement for $.mobile.changePage), passing the target and options.
<script>
// Delegate by page id — works for AJAX-loaded pages too
$(document).on("pagecreate", "#settings", function () {
var page = $(this);
page.find("#save").on("tap", function () {
alert("Saved settings");
});
});
// Use the pagecontainer widget (1.4+) for programmatic navigation
$(":mobile-pagecontainer").pagecontainer("change", "#settings", {
transition: "slide",
reverse: false
});
</script>Page Remove & Cleanup
By default jQuery Mobile removes a page from the DOM after you navigate away from it (unless domCache is on). pageremove fires right before removal — clean up intervals, listeners, or plugin instances here. The pagehide event's ui.prevPage gives the just-hidden page's jQuery object for teardown.
<script>
// Fires when a page is removed from the DOM (default behavior for
// non-cached pages after navigation away)
$(document).on("pageremove", function (e, ui) {
console.log("Page removed from DOM:", ui.prevPage);
});
// Clean up resources when a page is hidden for good
$(document).on("pagehide", "#temp", function () {
clearInterval($(this).data("timer"));
});
</script>Verwandte jQuery Mobile-Snippets
Copy-paste ready code for common tasks.
Page Structure
Multi-page template with header, content, and footer roles.
Page Transitions
Apply slide, pop, flip, and fade transitions between pages.
Toolbars
Fixed header and footer bars with fullscreen tap-to-toggle mode.
Navbars
Persistent icon-based navigation bars in the footer.
Listviews
Filterable, grouped lists with thumbnails, icons, and count bubbles.
Forms
Enhanced inputs including sliders, switches, and grouped controls.
Buttons
Themed, iconified, and grouped buttons from links and inputs.
Popup
Modal popups, dialogs, and tooltips with positioning control.
Was this helpful?