Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pjax Bundle Laravel Package

strontium/pjax-bundle

PJAX support for Symfony applications. This bundle adds middleware and Twig helpers to load page fragments via AJAX, update the URL and browser history, and enable faster navigation without a full SPA. Includes configurable selectors, request headers, and progressive enhancement for non-JS users.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the honest framing: this is a Symfony 2 bundle, not a Laravel package. There is no service provider, no facade, no config/pjax.php. Composer will happily install it, but StrontiumPjaxBundle extends Symfony\Component\HttpKernel\Bundle\Bundle and expects AppKernel registration, so it will do nothing inside a Laravel app. What you are actually evaluating is defunkt/jquery-pjax — roughly 400 lines of jQuery — plus a thin Symfony wrapper. Treat the bundle as documentation of a contract, not as a dependency.

Read in this order:

  1. The jquery-pjax README (the real spec — the bundle is a wrapper around it).
  2. The bundle's Resources/views/ and DependencyInjection/ directories — that's where any Twig helpers or request-listener logic lives, and it's a small surface area.
  3. Its composer.json — you'll find Symfony 2.x and PHP 5.x constraints. That tells you the maintenance status faster than the README does.

If you are actually on Symfony 2 (legacy app, which is the only place this belongs):

// app/AppKernel.php
new Strontium\PjaxBundle\StrontiumPjaxBundle(),

then publish the bundle assets and include the jQuery plugin in your layout after jQuery.

If you are on Laravel (the realistic case), skip the bundle and reproduce the contract in ~30 lines:

npm install jquery-pjax
{{-- layouts/app.blade.php --}}
<div id="pjax-container">
    @yield('content')
</div>

<script src="/js/jquery.js"></script>
<script src="/js/jquery.pjax.js"></script>
<script>
  $(document).pjax('a[data-pjax]', '#pjax-container', { timeout: 2000 });
</script>
// app/Http/Middleware/DetectPjax.php
public function handle($request, Closure $next)
{
    $response = $next($request);

    if ($request->header('X-PJAX')) {
        $response->headers->set('X-PJAX-Version', config('app.asset_version'));
    }

    return $response;
}

First use case: a content site where the header/footer/sidebar are expensive to re-render and the user mostly clicks article links. Wrap the article body in #pjax-container, opt links in with data-pjax, and return only that fragment when X-PJAX is present. If your app is a stateful dashboard, stop here — this is the wrong tool.

Implementation Patterns

Full-page vs. fragment rendering. The server must return the whole document for a cold load and only the container's contents for a pjax load. In Blade, that's a single conditional at the top of the controller or a response macro:

$view = $request->header('X-PJAX')
    ? view('articles._body', compact('article'))
    : view('articles.show', compact('article'));

return response($view);

Keep the fragment view and the full view sharing the same partial, or the two will drift and you'll get layout flashing on pjax navigation.

Middleware as the single detection point. Don't scatter header('X-PJAX') checks through controllers. Set a request attribute once and let views/controllers ask a question:

$request->attributes->set('pjax', $request->header('X-PJAX') !== null);
// Blade: @if(request()->attributes->get('pjax'))

A Request::macro('pjax', ...) is cleaner still and mirrors what the Symfony bundle's listener does.

Version header for cache busting. jquery-pjax sends and honors X-PJAX-Version. If the version in the response differs from the client's, pjax forces a full reload. Wire it to a build hash so deploys invalidate stale fragments automatically:

$response->headers->set('X-PJAX-Version', mix('js/app.js')->versionId ?? '1');

Re-initializing JavaScript. The classic pattern is to bind everything inside a pjax:end handler, or better, use event delegation from document for anything click-driven. Anything that must run per-page (date pickers, syntax highlighters, charts) goes in:

$(document).on('pjax:end', function () {
    hljs.highlightAll();
    initCharts();
});

Forms and non-GET. pjax only intercepts plain GET links. For forms, hook submit manually and use $.pjax({ url, type: 'POST', data, container }), and make sure your CSRF token is in the payload — the swapped fragment will not carry a fresh token.

Selective opt-in. Use a[data-pjax] rather than a as the selector. Blanket interception quietly breaks logout links, external links, download links, and anything with target="_blank".

Progressive enhancement discipline. Every pjax-enabled URL must also work as a plain HTTP request returning a full page. If it doesn't, you've built a JS-only app with extra steps.

Gotchas and Tips

  • The package is effectively abandoned. Three stars, zero dependents, Symfony 2-era constraints. Do not add it to a new project and do not expect PHP 8 or Laravel 10 compatibility. Vendor the jQuery plugin directly; it's MIT and tiny.
  • The response must contain the container. If #pjax-container is missing from the fragment, jquery-pjax silently falls back to a full page load and you'll spend an hour wondering why nothing is fast.
  • Scripts inside swapped fragments don't execute. jQuery's .html() strips <script> tags' execution semantics. Move all JS to pjax:end handlers, or use the $.pjax.defaults fragment-parsing path deliberately.
  • Scroll and title restoration are manual-ish. Title updates automatically from the <title> tag in the fragment; scroll position does not, unless you set scrollTo. Back-button restoration needs a pjax:popstate handler.
  • Analytics double-counting. pjax:end fires on every navigation; if your analytics snippet runs on page load and you also push a virtual pageview, you'll count twice. Use pjax:end as the only pageview trigger, or exclude the initial load.
  • Caching bites you silently. Browser caches fragments by URL. Add X-PJAX-Version or Cache-Control: no-cache on pjax responses until you're confident the fragments are versioned.
  • Debugging checklist: DevTools → Network → confirm the request carries X-PJAX: true; confirm the response is the fragment, not the layout; confirm the fragment contains the container selector; check the console for pjax:error and pjax:timeout events. Those two events are where 90% of failures surface.
  • Timeouts fall back to hard navigation. Default is 650ms. On a slow shared host, every pjax click turns into a full reload and the whole thing looks broken. Raise it or fix the latency.
  • Extension points are thin. The Symfony bundle gives you a request listener and possibly a Twig helper; there is no plugin architecture. Anything you need — form handling, container swapping on multiple regions, request cancellation — you write yourself against the jQuery plugin API.
  • Consider the modern alternatives before committing. htmx gives you the same fragment-swapping model with declarative attributes, no jQuery, and active maintenance. Laravel's Livewire covers the stateful case. Symfony's Turbo is the direct successor in spirit. If you're reaching for pjax in 2024, you're usually reaching for one of those instead — the only real reason to use pjax is a legacy jQuery codebase where adding a second paradigm isn't worth it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle