Part 1 of 4: Architectural Evolution in Horde 6
Turns out you can’t ship a stable release while depending on a framework that was deprecated five years ago. I sort of knew this deep down in my head. Yes, yes, unmaintained dependencies are a problem. But the full weight of it didn’t hit me until I started auditing Horde’s mobile interface code in preparation for Horde 6 stable. Our dear little project was dragging along not one dead javascript stack but two or three, depending on how you count. How to get out of this? What’s the deal? This is going to be part one of a four part series on how we are getting rid of jQuery Mobile and jQuery and how it is going to benefit desktop users mostly.
jQuery Mobile 1.3.2 was released in 2013. The jQuery Mobile project was officially deprecated in 2021. It receives no security updates, no bug fixes, no compatibility patches for modern browsers. Yet Horde’s entire mobile interface depends on it.
That’s a problem.
In today’s post I am going to tell you a story of how addressing that problem led me to rethink not just mobile UI but the entire approach to frontend development in Horde 6. It’s about technical debt, risk management and making architectural decisions that a volunteer project can actually sustain long-term.
The jQuery Mobile Era
Let me take you back to 2012-2013. The mobile web was exploding. Responsive design was new. Ethan Marcotte’s book came out in 2011. CSS3 was still bleeding edge and new features were adopted with some wariness. Flexbox existed but had terrible browser support. CSS Grid didn’t exist at all.
If you wanted a mobile-friendly web application, you had two realistic choices: build separate mobile templates from scratch, or use a framework. jQuery Mobile maybe wasn’t the leading framework for mobile web applications at the time but it had integration and brand recognition with its much more popular sister projects, jQuery and jQuery UI. It promised “write once, run anywhere” mobile interfaces in an era of browsers all doing their own thing in the most incompatible ways. With automatic styling, touch events, page transitions and an ecosystem of plugins it seemed like the right choice to get a mobile experience into Horde fast. Building a mobile interface from scratch would have taken years. jQuery Mobile gave us a prototype of a working mobile interface relatively quickly. Horde was a side project to some of the developers back then but a business to others. Adding mobile views promised to attract sponsoring from major sites.
And it worked. For a while.
When Frameworks Get Deprecated
The jQuery Mobile project effectively stopped development after 1.4.5 in 2014. A 1.5.0 release came in 2016 but was mostly maintenance. The project was officially deprecated in October 2021. Developers please migrate off the write once run anywhere framework. Horde didn’t. Mobile did not get the traction yet needed to compete with Horde’s other major concerns. Mobile was far from feature parity to desktop app, making it of limited value to end users. Limited value to end users meant little priority and the jQuery framework went out of the lime light but was still actively maintained and not going away quite yet.
But that’s only part of it. Here’s the thing about framework deprecation: it doesn’t just mean “no new features.” It means:
- No security patches: Browser vendors change behavior and industry sensitivities develop. When security vulnerabilities get discovered who is going to fix them?
- No compatibility updates: Modern browsers break old assumptions but the framework doesn’t adapt. Many reasons to choose a cross browser framework vanished over time.
- No community support: Stack Overflow answers dry up. Documentation sites disappear or reference outdated examples.
- Talent drain: Developers who knew the framework move on. Few really understand the code base.
Only a few tips of this iceberg were visible back then but we could have guessed maybe.
Audit Time!
I started with a simple question: how much jQuery Mobile code does Horde actually use?
This required reading through our mobile templates, tracking which jQuery Mobile widgets we depend on. I counted JavaScript method calls and CSS usage. The process took several days of systematic searching through the codebase even though I had some throwaway scripts to make it tenable. I’ve got a job to do after all and Horde isn’t an official part of it anymore.
The results were underwhelming.
Widgets in use: 10 out of 30+ available widgets
- Listview (for navigation menus)
- Button (styled buttons)
- Toolbar (header/footer bars)
- Navbar (tab navigation – and barely put to real use!)
- Collapsible (expandable sections)
- Popup (modal dialogs)
- Panel (side menus)
- Loader (loading spinners were popular back then)
- Textinput (form fields)
- Selectmenu (dropdowns)
JavaScript methods: 3 out of dozens available
.page()for page initialization.popup()for modal dialogs.listview('refresh')for updating lists
CSS classes: Heavy usage, but mostly for basic styling
ui-btnfor button appearanceui-barfor toolbarsui-contentfor content paddingui-listviewfor list stylingdata-roleattributes driving most behavior
To sum it up: About 90% of what I initially thought was “jQuery Mobile functionality” was just CSS styling. The framework was applying classes based on data-role attributes, but the actual behavior was minimal.
We were using approximately 5% of jQuery Mobile’s capabilities.
But for that 5% we were shipping:
- jQuery: 96 KB
- jQuery Mobile JavaScript: 125 KB
- jQuery Mobile CSS: 115 KB
- Icon images: ~5 MB (743 PNGs per theme)
Total payload: ~488 KB of code + 5 MB of images on first page load.
For 5% utilization. Now that’s not really mobile friendly. When you’re on a hiking trip and just want to check some item for peace of mind, this is a major frustration.
A Framework Lock-In Problem
Here’s where it gets uncomfortable. jQuery Mobile is deprecated. What do we migrate to?
I have been looking at the landscape of JS UI frameworks time and again since the 2020s:
React: Popular, well-maintained, massive ecosystem. But requires a complete architectural shift. Horde’s server-rendered PHP templates would need to become API endpoints. The entire application structure changes. I did some React-first inhouse projects in my former company. While I liked the design, major efforts to integrate it with Horde based custom apps written before turned out thorny business. It is really meant to be used as part of a Typescript or other compile-to-javascript pipeline with dependency management and many other aspects of the modern JS ecosystem which I don’t find appealing.
Vue: Similar story. Very popular framework. Quite some BC breaks between versions. But incompatible with where we are coming from.
Framework7: Specifically designed for mobile hybrid apps. Better fit, but smaller community. Is this going to be available five years from now?
Ionic: Also designed for hybrid apps. Heavy focus on Angular/React/Vue integration. Same architectural questions.
Bootstrap: General-purpose, but mobile-first. Could work, but still a large dependency for features we don’t need.
Some years passed and developers were busy keeping Horde’s core functionality compatible with a changing ecosystem. I knew it and thought about it with some dread: This problem won’t go away, it will only fester. It was not a main concern as the core Horde tools had good sync-to-mobile integrations: CalDAV, CardDAV, ActiveSync. I did some proof of concept for Thunderbird plugin integration but just as I started to going they broke/modernized their plugin ecosystem. Mozilla also was a bit discouraging with their policy towards Thunderbird. Sigh.
I was looking forward to having this exact conversation again five years down the line. “Framework X was great in 2026, but now it’s 2031 and everyone’s moved on to Framework Y. We need to rewrite.”
For a volunteer open source project with limited resources, this cycle is unsustainable.
Every framework migration means:
- Months of development time rewriting working code
- Risk of regressions and bugs
- Documentation updates
- Trying to explain to fellow developers and incidental contributors why any of this is necessary right now
- Testing across all applications
We can’t keep doing this every five years.
Vanilla Web Revelations
Modern CSS is shockingly capable. It took me a while to understand that. I’m not very good at CSS but my wife is a trained media designer and I also consulted some friends on my worries.
I started experimenting with what you could build using only modern web standards. No frameworks, no libraries, just CSS3 and modern JavaScript. I wasn’t tabooing third party libraries and utilities but I wanted to see how far it would get me.
CSS Grid (widely supported since 2017): Handles complex layouts that used to require framework grid systems.
CSS Flexbox (widely supported since 2015): Handles most layout needs—centering, alignment, distribution.
CSS Variables (widely supported since 2016): Runtime theming without build tools or preprocessors. One less step crying for an ever-changing tool chain just to test your latest three line change.
CSS Media Queries (ancient, universally supported): Responsive breakpoints.
CSS @layer (supported since 2022): Manage specificity and style precedence.
Native HTML5 elements: <details> replaces collapsible widgets, <dialog> replaces modal popups, <progress> replaces custom loaders.
Here’s what shocked me: There’s nothing left of what jQuery Mobile and in general jQuery did for Horde’s limited needs. It’s all possible without a fat glue layer evening the field across browsers. Another way the world has changed: Latest versions of browsers are available almost universally. The share of users who use 12 to 36 month old versions of major browsers is almost zero. While fringe and mobile browsers still don’t support all features of chromium-based and mozilla-based desktop browsers in their latest versions, old browser versions are almost a non-issue.
Example: Theme Switching
jQuery Mobile themes required:
- 5-10 MB of PNG icons per theme
- Separate CSS files per theme (100+ KB each)
- JavaScript theme switching that reloaded pages
- Build process to generate theme variations
Vanilla CSS with CSS Variables:
/* themes/blue/tokens.css - just 2 KB */
:root {
--color-primary: #0066cc;
--color-primary-dark: #004c99;
--color-bg: #ffffff;
--color-text: #333333;
--color-border: #dddddd;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--border-radius: 4px;
--shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Automatic dark mode based on system preference */
@media (prefers-color-scheme: dark) {
:root {
--color-primary: #4488ff;
--color-primary-dark: #6699ff;
--color-bg: #1a1a1a;
--color-text: #e0e0e0;
--color-border: #333333;
--shadow: 0 2px 4px rgba(0,0,0,0.3);
}
}
/* Components use variables */
.button {
background: var(--color-primary);
color: var(--color-bg);
padding: var(--space-md);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
}
.button:hover {
background: var(--color-primary-dark);
}
That’s it. No build tools. No webpack. No SASS compilation. Just load a different token file and the entire interface updates instantly.
Dark mode support could even respect the user’s system preference. Want to override it? Load a different theme file. Theme files are 2-5 KB each. I am not quite there yet. I have implemented dark mode as a separate theme and it’s a palette swapped knock-off default theme. Did I just tell you I’m not good at CSS and appreciate any help?
Example: Responsive Layouts
jQuery Mobile grid system:
<div class="ui-grid-a">
<div class="ui-block-a">Column 1</div>
<div class="ui-block-b">Column 2</div>
</div>
Required framework CSS to interpret ui-grid-a and ui-block-* classes.
CSS Grid (no framework):
.app-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--space-md);
}
<div class="app-grid">
<div>Column 1</div>
<div>Column 2</div>
</div>
The layout is responsive automatically. Columns wrap to rows on narrow screens without media queries. The browser handles it. The opposite is not quite true, not yet. Our trivial mobile-first PoC doesn’t leverage additional screen estate in a good way. But we have all the tools to build that into it.
Example: Native HTML5 Widgets
jQuery Mobile collapsible:
<div data-role="collapsible">
<h3>Advanced Options</h3>
<div>Content here</div>
</div>
Required jQuery Mobile JavaScript (~125 KB) to handle click events, animations, state management.
Native HTML5 <details>:
<details>
<summary>Advanced Options</summary>
<div>Content here</div>
</details>
Zero JavaScript. Fully accessible. Works everywhere I tested. Browser handles keyboard navigation, ARIA attributes, animations.
Performance Math
Not to be confused with performative math. Let’s do the actual math on what users download.
jQuery Mobile stack (what we had):
- jQuery: 96 KB
- jQuery Mobile JS: 125 KB
- jQuery Mobile CSS: 115 KB
- Mobile app JavaScript (8 apps): 90 KB
- jQuery Mobile theme: 115 KB
- Icons (PNG, 743 files): ~5 MB
Total first load: ~488 KB JavaScript/CSS + 5 MB images
Subsequent page loads still hit ~350 KB because JavaScript/CSS isn’t fully cached across page navigations in jQuery Mobile’s architecture.
Vanilla responsive stack (what we built):
- Core responsive JavaScript: 25 KB
- Responsive CSS: 15 KB
- Theme tokens: 2-5 KB
- Icons (SVG sprite): 100 KB
- Mobile app JavaScript – evolving but I am pretty sure to reach feature parity with previous mobile screens with less than 100 KB summed across apps.
Total first load: ~70 KB JavaScript/CSS + 100 KB images
That’s 85% smaller for code and 98% smaller for images.
For users on slow connections that’s a blessing and it doesn’t hurt others either. Mobile users in rural areas. Users with expensive or limited data plans. Users in developing countries or Germany.
The Decision: Mobile-First Migration Strategy
So vanilla CSS could replace jQuery Mobile. The question became: how do we migrate without destabilizing the entire platform?
Horde has two frontend codebases:
- Desktop interface: PrototypeJS-based, stable, works, users know it
- Mobile interface: jQuery Mobile-based, incomplete, deprecated dependencies
The obvious instinct: migrate the desktop interface first because it has more users and more functionality.
I made the opposite choice: Start with mobile.
Here’s why:
Risk Management
Desktop is stable. Users depend on it. It works. PrototypeJS is old (2005-2015 era) but it’s not deprecated—the code still runs fine in modern browsers. There’s no urgent security problem forcing our hand. We will however begin to evolve the delivery basis. The way ajax works in these apps. The way pages are delivered through exposed php pages rather than routes. Some ball of mud problems which need to be untangled for performance.
Mobile is incomplete. The mobile interface was always a subset of functionality. Users expect it to be limited. Mobile users probably aren’t thrilled by what we delivered for years and will accept anything more modern willingly.
If we break something in the mobile interface during migration, the blast radius is contained. Users can switch to desktop view as a workaround. If we break the desktop interface, we’ve disrupted the primary workflow for thousands of users with no fallback.
Incremental Progress
Starting with mobile means we can ship improvements incrementally:
- Phase 0: Login (✅ completed) – Responsive login page, all users
- Phase 1: Portal (✅ completed) – App launcher, mobile portal replacement
- Phase 2: Guest pages (in progress) – Public calendars, wikis, ticket forms
- Phase 3: Apps (planned) – Nag, Ansel, Turba, Gollem, etc.
Each phase delivers value without requiring complete migration. Users benefit immediately. Development can proceed at sustainable pace.
Contrast this with “desktop first” which would require:
- Replacing PrototypeJS across all apps simultaneously (too risky)
- Building feature parity before shipping anything (too slow)
- Higher coordination overhead (more developers, more testing)
Validation Before Commitment
By starting with mobile, we validate the vanilla CSS approach on a smaller surface area before committing to desktop migration.
If the approach has problems, we can learn from it. Adopting a framework or discrete helper libraries into a vanilla code base is always possible. Performance issues? Browser incompatibilities? Maintenance difficulties? Learn to deal with them when they pop up.
If the approach works well then we have confidence to expand it to desktop in Horde 7.
Parallel Development
Mobile-first doesn’t block other work. Of course it costs time. Desktop PrototypeJS interface continues working unchanged. Team can work on responsive mobile views and desktop features in parallel without conflicts.
This matters for volunteer open source—contributors. We want to attract contributions from those who are not married to Horde but have an itch to scratch, a feature to improve, a real world use case to share. Our core team works on different features at different times. Parallel tracks let development continue without waiting for migration completion. The need to be complete is a real release killer.
What We Built So Far
The responsive login and mobile portal shipped with Horde 6.
Responsive Login
Single login page works on all devices:
- Desktop: full-width layout, traditional appearance
- Tablet: centered layout, touch-friendly controls
- Phone: full-screen, large touch targets
Dark mode support: Respects prefers-color-scheme to some extent automatically. Users on macOS/iOS/Android/Windows with system dark mode enabled get dark login automatically. It doesn’t work all that well on the rest of the screens yet.
No framework dependencies: Pure HTML5, CSS3, vanilla JavaScript.
Backwards compatible: All authentication backends work unchanged (LDAP, SQL, IMAP, custom). We also ported the logic to add fields for 2FA if the respective API is present.
Size: ~5 KB total (HTML, CSS, minimal JS for form validation).
Mobile Portal
App launcher for mobile/tablet browsers:
Grid layout: Responsive grid using CSS Grid, wraps automatically based on screen width.
App icons: SVG sprite sheet, single 100 KB file contains all icons for all apps, theme-independent.
Touch-friendly: Large tap targets (48×48 pixels minimum), proper spacing, no accidental clicks.
Fast: Initial load ~70 KB, subsequent navigations use cached resources.
Theme support: Dark and red themes included, more coming, 2-5 KB per theme.
What Changed for Users
Mobile/tablet users: Immediately see the new responsive login. After login, they get the new mobile portal (detected by user agent). Significantly faster load times, modern appearance, better touch experience.
Desktop users: See the responsive login but after login, they get the same PrototypeJS portal they’ve always had. No disruption to workflow.
Administrators: No configuration changes required. The responsive views are automatic based on browser user agent. No feature flags to toggle.
Framework Fatigue Problem
Here’s the philosophical point that matters most for Horde’s long-term sustainability.
Horde is a volunteer open source project. We don’t have dedicated frontend teams with designers, React specialists, build tool experts, accessibility consultants. We have PHP developers who contribute in their spare time.
Every framework we adopt has a learning curve:
- How does the framework structure components?
- What’s the data flow model?
- How do we integrate with server-rendered PHP?
- What’s the build toolchain?
- How do we debug when things break?
And every framework eventually becomes legacy:
- jQuery was cutting-edge in 2006, legacy by 2020
- jQuery Mobile was cutting-edge in 2012, deprecated by 2021
- Angular 1 was cutting-edge in 2010, replaced by Angular 2+ (complete rewrite)
- React is dominant in 2024, but who knows about 2030?
We can’t do that with the capacity we have these days.
Web standards don’t deprecate so fast. CSS Grid from 2017 still works perfectly in 2026. It will work in 2030. The browser vendors maintain backwards compatibility because billions of websites depend on these standards.
By building on web standards instead of frameworks, we’re making a bet on stability. The code we write today will still work in five years without a migration treadmill.
This is the economic argument for vanilla web development in volunteer projects: maintenance burden matters more than developer convenience.
Lessons Learned
Technical Debt Compounds
jQuery Mobile was deprecated in 2021. I didn’t start seriously addressing it until 2024-2025. That three-year delay made the problem worse:
- Browser vendors changed behavior
- Security concerns grew
- Alternative frameworks came and went
- Technical debt piled up elsewhere
The lesson: address deprecated dependencies quickly, not eventually.
Audits Reveal Surprises
I thought Horde used jQuery Mobile extensively. The audit showed 5% utilization. Without the audit I might have migrated to another heavy framework instead of realizing vanilla CSS could handle it. In fact a few years back I tried exactly that.
The lesson: Measure before deciding. Assumptions about dependency usage are often wrong.
Risk Management Over Speed
Starting with mobile instead of desktop felt slower. I was not super sure this was the right way at first. The mobile interface has fewer users, less functionality. But the risk reduction was worth it. I validated the approach without betting the farm.
The lesson: In architectural changes, risk management is more valuable than speed.
Frameworks Are Liabilities
Every framework dependency is a future maintenance burden. Not “might be”. Will be. The question is just when.
For volunteer projects especially, minimizing framework dependencies reduces long-term maintenance burden at the cost of upfront development time. That tradeoff is usually worth it.
The lesson: Choose boring technology. Web standards are boring. They’re also stable. There’s lessons in this for Horde’s PHP parts and the way it embraces PHP-FIG standards.
What’s Next (maybe)
The responsive login and mobile portal are shipped. jQuery Mobile is not yet removed from core Horde. The apps still load it. That is a break in style and technology which I want to eliminate one app at a time.
Next phases:
Guest page templates: Public calendars (Kronolith), wiki pages (Wicked), ticket forms (Whups) will get responsive templates. These are high-value because they’re often the first thing non-users see. A modern responsive public calendar is good marketing.
App migration: Starting with simpler apps (Nag for tasks, Ansel for photos) and moving to more complex apps (Turba for contacts, Kronolith for calendars, IMP for email). Each app gets responsive templates incrementally.
Desktop migration: Eventually. Horde 7 timeframe. By then we’ll have validated the responsive approach thoroughly on mobile and can migrate desktop with confidence.
This will take years. That’s fine. Incremental progress beats stalled rewrites.
The Bigger Picture
This isn’t just about jQuery Mobile. It’s about making architectural decisions that a volunteer project can sustain long-term.
Horde has been around since 2000. We’ve survived shifting trends—Ajax, Web 2.0, mobile revolution, SPA frameworks, Node.js everything. We’ve survived by being conservative about dependencies and prioritizing stability. Ironically, sometimes we dodged the bullets because we weren’t fast enough.
The jQuery Mobile migration continues that philosophy. Use web standards, avoid framework churn, make incremental progress, don’t break production deployments.
Boring? Yes. Sustainable? Also yes.
For a volunteer project maintaining software that thousands of organizations depend on, sustainability beats excitement every time.
Coming up in Part 2: JWT authentication architecture and the hybrid model that provides the foundation for modern API access and enterprise SSO integration.
This is Part 1 of a 4-part series on Horde 6’s architectural evolution. Part 2 covers JWT authentication, Part 3 covers vanilla web sustainability, and Part 4 covers developer infrastructure improvements.
Leave a Reply