jarir-ahmed/universal-spa

A framework-agnostic Single Page Application (SPA) engine for PHP

Maintainers

Package info

github.com/jarir2020/universal-spa

pkg:composer/jarir-ahmed/universal-spa

Statistics

Installs: 7

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-06-15 11:21 UTC

This package is auto-updated.

Last update: 2026-06-15 11:23:57 UTC


README

A lightning-fast, zero-reload Single Page Application (SPA) engine for any PHP Framework (Laravel, CodeIgniter, Symfony, Slim, or even raw PHP).

Two Modes

This package empowers you with two distinct approaches:

1. HTML Mode (Zero Backend Required)

In this mode, the frontend JavaScript fetches the full HTML page, parses it in the browser using DOMParser, and swaps out the body. Pros: Requires ZERO PHP changes. Works with static sites or any backend.

2. JSON Mode (Bandwidth Optimized)

In this mode, the PHP backend intercepts the response buffer, parses the HTML, and sends only the required parts (Title, Body, Styles, Scripts, Meta) as a tiny JSON object. Pros: Faster network transfer.

Installation

composer require jarir-ahmed/universal-spa

Setup (JSON Mode)

  1. Put this at the very top of your PHP application (e.g., public/index.php or as a middleware):
\JarirAhmed\UniversalSpa\SpaEngine::start();
  1. Add data-spa-content to your main wrapper in your HTML layout:
<main data-spa-content>
    <!-- Your page content goes here -->
</main>
  1. Add the data-spa attribute to any links you want to feel instant:
<a href="/about" data-spa>About Us</a>
  1. Include the JS script and initialize it:
<script src="path/to/resources/js/jarir-spa.js"></script>
<script>
    new JarirSpa({
        mode: 'json' // or 'html'
    });
</script>

Configuration Options

All options are passed to the JarirSpa constructor:

<script>
    new JarirSpa({
        mode: 'json',                    // 'json' or 'html' (default: 'html')
        contentSelector: '[data-spa-content]', // CSS selector for content container
        progressBar: true,                // Show loading progress bar (default: true)
        transition: true,                 // Enable fade transitions (default: true)
        transitionDuration: 200,          // Transition duration in ms (default: 200)
        progressBarColor: 'linear-gradient(90deg, #4f46e5, #06b6d4)' // Progress bar color
    });
</script>

Features

  • Framework Agnostic — Works with Laravel, Symfony, CodeIgniter, Slim, CakePHP, raw PHP
  • Two Modes — HTML mode (zero backend changes) or JSON mode (bandwidth optimized)
  • Hover Prefetching — Links are prefetched on hover for instant loads
  • Loading Progress Bar — Slim animated bar at top during navigation (like YouTube/GitHub)
  • Smooth Page Transitions — Configurable fade-out/fade-in animations
  • Inline Script Execution — Scripts inside swapped content are properly re-executed
  • CSS Scoping — Old page styles are removed and new ones injected on navigation
  • Meta Tag Updates — Updates <meta> description and Open Graph tags on navigation
  • Browser History Support — Back/forward buttons work via pushState/popstate
  • Active Navigation — Auto-toggles active class on SPA links
  • Smart Link Filtering — Only intercepts data-spa links; external links work normally
  • Graceful Fallback — Falls back to full-page navigation on errors
  • Custom Events — Dispatches spa:navigated event for extensibility
  • Lightweight — ~10KB JS, ~3KB PHP. No external dependencies.

Layout vs Page Styles/Scripts

Mark your layout (persistent) styles and scripts so they're never removed on navigation:

<!-- Layout style — persists across navigations -->
<style data-spa-layout-style>
    body { font-family: sans-serif; }
    nav { background: #333; }
</style>

<!-- Page-specific style — swapped automatically on navigation -->
<style>
    .hero { background: blue; }
</style>

<!-- Layout script — runs once, never re-executed -->
<script data-spa-layout-script>
    new JarirSpa({ mode: 'json' });
</script>

Events

Listen for navigation events:

document.addEventListener('spa:navigated', (e) => {
    console.log('Navigated to:', e.detail.url);
    console.log('Page title:', e.detail.title);
    // Re-init your widgets, analytics, etc.
});

License

MIT