AboutBlogContact
Frontend EngineeringMarch 10, 2014 5 min read 152Updated: June 22, 2026

Transitioning from jQuery Mobile to Modern Frameworks: A Retrospective

AunimedaAunimeda
📋 Table of Contents

jQuery Mobile 1.0 released in November 2011. Its pitch was compelling: build a mobile app using HTML, CSS, and jQuery, with native-looking UI components for iOS, Android, and BlackBerry. The data-role attribute system made mobile-styled components as simple as adding attributes to existing HTML.

We built 12 projects on jQuery Mobile between 2011 and 2013. We stopped using it in 2014. Looking back at those projects now - some still running, most replaced - the story is instructive.


Why jQuery Mobile Won in 2011

For a web developer in 2011, native iOS/Android development was a hard barrier. Objective-C had a steep learning curve and required a Mac. Java for Android was verbose. Both required understanding mobile-specific SDKs.

jQuery Mobile offered a gentle ramp: if you knew HTML and jQuery, you could build something that looked like a native app within a day.

<!-- jQuery Mobile 1.1 - a complete mobile app page -->
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css">
    <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
</head>
<body>
    <div data-role="page" id="home">
        <div data-role="header">
            <h1>Product Catalog</h1>
            <a href="#cart" class="ui-btn-right" data-icon="shopping-cart">Cart</a>
        </div>
        <div data-role="content">
            <ul data-role="listview" data-filter="true" data-filter-placeholder="Search...">
                <li data-role="list-divider">New Arrivals</li>
                <li>
                    <a href="#product-1">
                        <img src="/images/product1.jpg" class="ui-li-thumb">
                        <h2>Wireless Headphones</h2>
                        <p>$89.99 · In Stock</p>
                        <p class="ui-li-aside"><strong>New</strong></p>
                    </a>
                </li>
            </ul>
        </div>
        <div data-role="footer" data-position="fixed">
            <div data-role="navbar">
                <ul>
                    <li><a href="#home" data-icon="home" class="ui-btn-active">Home</a></li>
                    <li><a href="#categories" data-icon="grid">Browse</a></li>
                    <li><a href="#account" data-icon="user">Account</a></li>
                </ul>
            </div>
        </div>
    </div>
</body>
</html>

No JavaScript beyond the library includes. The data-role attributes did everything: listview with data-filter="true" automatically added a live search filter. data-position="fixed" kept the footer visible on scroll. It was impressive for 100 lines of HTML.


The Performance Wall

jQuery Mobile's architecture had a fatal flaw: it enhanced the entire DOM on page load. Every data-role attribute triggered a scan and enhancement. On a page with 50 list items, this was fast. On a page with 500, it was 400ms of JavaScript before the user saw anything.

The 300ms touch delay (iOS Safari's default delay to distinguish tap from double-tap) was compounded by jQuery Mobile's event handling overhead. Scrolling was GPU-accelerated on native apps; jQuery Mobile's scroll was the browser default - noticeably slower.

We tried every optimization:

// Lazy initialization - only enhance visible elements
$(document).on("pagebeforeshow", "#product-list", function() {
    // Only enhance the listview when the page is about to show
    var listview = $(this).find('[data-role="listview"]');
    if (!listview.data('mobile-listview')) {
        listview.listview();
    }
});

// Disable AJAX page transitions (the main performance killer)
$.mobile.ajaxEnabled = false;

// Disable history management
$.mobile.pushStateEnabled = false;

// Remove transition animations entirely
$.mobile.defaultPageTransition = 'none';

Disabling animations made jQuery Mobile apps faster. It also made them feel exactly like websites. We were left with the worst of both worlds: slower than native, looking worse than mobile web.


What We Learned From The Failures

Project 1 (Product catalog, 2012): 3,000 SKUs. Initial load took 8 seconds on iPhone 4. We paginated to 50 items per page and it became acceptable, but the search filter (jQuery Mobile's built-in listview filter) queried the DOM, not the server - it could only filter visible items. We had to rebuild search with AJAX. Half the jQuery Mobile benefit disappeared.

Project 4 (Restaurant ordering, 2013): Complex cart state. jQuery Mobile's page-based navigation (each page was a <div data-role="page">) stored state in DOM elements across page transitions. After 5 navigation steps forward and back, the DOM had accumulated duplicate page elements. Memory usage grew. We built a custom cleanup routine that ran on every page transition to remove old page DOM nodes.

Project 8 (Corporate directory, 2013): Client wanted offline support. jQuery Mobile had no offline story. We built offline sync using localStorage and a custom sync library. At this point we were maintaining jQuery Mobile as a UI layer while writing all the actual application logic ourselves. The framework was providing CSS themes and nothing else.


The Migration to Backbone + Custom UI

By mid-2013 we started migrating jQuery Mobile projects to Backbone.js with hand-coded CSS. More work upfront, vastly better outcomes:

// The jQuery Mobile listview in pure JS + CSS
var ProductListView = Backbone.View.extend({
    tagName: 'ul',
    className: 'product-list',
    
    initialize: function() {
        this.listenTo(this.collection, 'reset', this.render);
        this.listenTo(this.collection, 'add', this.renderProduct);
    },
    
    render: function() {
        this.$el.empty();
        this.collection.each(this.renderProduct, this);
        return this;
    },
    
    renderProduct: function(product) {
        var view = new ProductItemView({ model: product });
        this.$el.append(view.render().el);
    },
    
    filter: function(searchTerm) {
        // Filter against ALL products, not just visible ones
        // Then trigger a server-side search if needed
        if (searchTerm.length > 2) {
            this.collection.fetch({ 
                data: { search: searchTerm },
                reset: true 
            });
        }
    }
});
/* Custom mobile-optimized CSS - 100 lines, zero framework overhead */
.product-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.product-list li {
    display: flex;
    align-items: center;
    padding: 12px 16px;
    border-bottom: 1px solid #eee;
    min-height: 60px;   /* Touch-friendly */
    -webkit-tap-highlight-color: rgba(0,0,0,0.1);
}

.product-list li:active {
    background-color: #f5f5f5;  /* Touch feedback */
}

First render: 40ms vs jQuery Mobile's 400ms. The difference was entirely in not scanning and enhancing the DOM.


The Verdict

jQuery Mobile was the right answer for 2011. It lowered the barrier to mobile web development, shipped apps that clients could use, and established mobile UI patterns that influenced later frameworks.

It wasn't the right answer for 2014. Framework bloat, performance limitations, and the proliferation of mobile-optimized CSS techniques made hand-crafted solutions both faster and simpler.

The lesson from jQuery Mobile's arc: frameworks that succeed by lowering barriers often carry the weight of that design decision as the ecosystem matures. What made jQuery Mobile accessible in 2011 - the declarative data-role enhancement system - was what made it slow in 2013.

The frameworks that replaced it (React, Vue, Ionic) learned from its mistakes: component-based rather than DOM-scanning, explicit lifecycle rather than automatic enhancement, and performance as a first-class design constraint.


Aunimeda builds modern web frontends - from single-page applications to complex multi-locale sites.

Contact us to discuss your frontend project. See also: Web Development, Corporate Website Development

Read Also

How to Set Up React with Webpack 1.x Without Create React App (2015)aunimeda
Frontend Engineering

How to Set Up React with Webpack 1.x Without Create React App (2015)

In 2015, Create React App didn't exist. Setting up React meant manually configuring Webpack 1.x, Babel 5, and Hot Module Replacement. Here's the exact working config we used in production - and why each piece was necessary.

The jQuery Era (2008-2015): When One Library United the Webaunimeda
Frontend Engineering

The jQuery Era (2008-2015): When One Library United the Web

Before React, Vue, or Angular, there was jQuery. For seven years it was the answer to virtually every frontend problem. We wrote hundreds of thousands of lines of jQuery code. Here's what that era actually looked like - and what it taught us that still applies.

How We Handled Mobile-First Design in 2012aunimeda
Frontend Engineering

How We Handled Mobile-First Design in 2012

In 2012 we made a company decision: every new project starts with the mobile wireframe, not the desktop. Here's the process we built, the client conversations we had, and the mistakes we made along the way.

Need IT development for your business?

We build websites, mobile apps and AI solutions. Free consultation.

Web Development

Get Consultation All articles