Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
P

pjax

> 编程语言
Open source

Easily enable fast Ajax navigation on any website (using pushState + xhr)

1.5K stars0 likes2 views
WebsiteGitHub

About

Easily enable fast Ajax navigation on any website (using pushState + xhr)

Pjax

.

Easily enable fast AJAX navigation on any website (using pushState() + XHR)

Pjax is a standalone JavaScript module that uses AJAX (XmlHttpRequest) and pushState() to deliver a fast browsing experience.

It allows you to completely transform the user experience of standard websites (server-side generated or static ones) to make users feel like they are browsing an app, especially for those with low bandwidth connections.

No more full page reloads. No more multiple HTTP requests.

Pjax does not rely on other libraries, like jQuery or similar. It is written entirely in vanilla JS.

Installation

  • You can link directly to the bundle:

    xml
    <script src="https://cdn.jsdelivr.net/npm/pjax@VERSION/pjax.js"></script>
  • Or the minified bundle:

    xml
    <script src="https://cdn.jsdelivr.net/npm/pjax@VERSION/pjax.min.js"></script>
  • You can also install Pjax from npm:

    bash
    npm install pjax

    Note: If you use this option, you will need to do one of the following:

    • Link a script tag to either pjax.js or pjax.min.js. E.g.:
    xml
    <script src="./node_modules/pjax/pjax.js"></script>
    • Use a bundler like Webpack. (index.js cannot be used in the browser without a bundler).
  • Or you can clone the repo and build the bundle from the source using npm:

    bash
    git clone https://github.com/MoOx/pjax.git
    cd pjax
    npm install
    npm run build

    and then link a script tag to either pjax.js or pjax.min.js. E.g.:

    xml
    <script src="./pjax.min.js"></script>

What Pjax Does

Under the hood, it's just ONE HTTP request with a pushState() call.

Pjax loads pages using AJAX and updates the browser's current URL using pushState() without reloading your page's layout or any resources (JS, CSS), giving a fast page load.

It works with all permalinks and can update all the parts of the page you want (including HTML metas, title, and navigation state).

In the case of browsers that don't support history.pushState(), Pjax gracefully degrades and does not do anything at all.

Additionally, Pjax:

  • Is not limited to one container, like jQuery-Pjax is.
  • Fully supports browser history (back and forward buttons).
  • Supports keyboard browsing.
  • Automatically falls back to standard navigation for external pages (thanks to Captain Obvious's help).
  • Automatically falls back to standard navigation for internal pages that do not have an appropriate DOM tree.
  • Allows for CSS transitions (animations) very easily.
  • Is only around 6kb (minified and gzipped).

How Pjax Works

  • It listens to every click on links you want (by default all of them).
  • When an internal link is clicked, Pjax fetches the page's HTML via AJAX.
  • Pjax renders the page's DOM tree (without loading any resources - images, CSS, JS, etc).
  • It checks that all defined parts can be replaced:
    • If the page doesn't meet the requirements, standard navigation is used.
    • If the page meets the requirements, Pjax does all defined DOM replacements.
  • Then it updates the browser's current URL using pushState().

Overview

Pjax is fully automatic. You don't need to change anything about your existing HTML, you just need to designate which elements on your page that you want to be replaced when your site is navigated.

Consider the following page.

…

We want Pjax to intercept the URL /about, and replace .the-content with the resulting content of the request.

It would also be nice if we could replace the <nav> to show that the /about link is active, as well as update our page meta and the <aside> sidebar.

So all in all we want to update the page title and meta, header, content area, and sidebar, without reloading styles or scripts.

We can easily do this by telling Pjax to listen on all a tags (which is the default) and use CSS selectors defined above (without forgetting minimal meta):

javascript
var pjax = new Pjax({
  selectors: [
    "title",
    "meta[name=description]",
    ".the-header",
    ".the-content",
    ".the-sidebar",
  ]
})

Now, when someone in a Pjax-compatible browser clicks an internal link on the page, the content of each of the selectors will be replaced with the specific content pieces found in the next page's content.

Magic! For real! There is no need to do anything server-side!

Differences with jQuery-pjax

  • No jQuery dependency.
  • Not limited to a container.
  • No server-side requirements.
  • Works for CommonJS environment (Webpack/Browserify), AMD (RequireJS) or even globally.
  • Allows page transitions with CSS animations.
  • Can be easily tweaked, since every method is public (and as a result, overridable).

Compatibility

Pjax only works with browsers that support the history.pushState() API. When the API isn't supported, Pjax goes into fallback mode (and it just does nothing).

To see if Pjax is actually supported by your browser, use Pjax.isSupported().

Usage

new Pjax()

Let's talk more about the most basic way to get started.

When instantiating Pjax, you can pass options into the constructor as an object:

javascript
var pjax = new Pjax({
  elements: "a", // default is "a[href], form[action]"
  selectors: ["title", ".the-header", ".the-content", ".the-sidebar"]
})

This will enable Pjax on all links, and designate the part to replace using CSS selectors "title", ".the-header", ".the-content", ".the-sidebar".

In some cases, you might want to only target some specific elements to apply Pjax behavior. In that case, you can do two different things:

  1. Use a custom CSS selector( such as "a.js-Pjax" or ".js-Pjax a", etc).
  2. Override Pjax.prototype.getElements.
    • Note: If doing this, make sure to return a NodeList.
javascript
// use case 1
var pjax = new Pjax({ elements: "a.js-Pjax" })
javascript
// use case 2
Pjax.prototype.getElements = function() {
  return document.getElementsByClassName(".js-Pjax")
}

var pjax = new Pjax()

loadUrl(href, [options])

With this method, you can manually trigger the loading of a URL:

javascript
var pjax = new Pjax()

// use case 1
pjax.loadUrl("/your-url")

// use case 2 (with options override)
pjax.loadUrl("/your-other-url", { timeout: 10 })

handleResponse(responseText, request, href, options)

This method takes the raw response, processes the URL, then calls pjax.loadContent() to actually load it into the DOM.

It is passed the following arguments:

  • responseText (string): This is the raw response text. This is equivalent to request.responseText.
  • request (XMLHttpRequest): This is the XHR object.
  • href (string): This is the URL that was passed to loadUrl().
  • options (object): This is an object with the options for this request. The structure basically matches the regular options object, with a few extra internal properties.

You can override this if you want to process the data before, or instead of, it being loaded into the DOM.

For example, if you want to check for a non-HTML response, you could do the following:

javascript
var pjax = new Pjax();

pjax._handleResponse = pjax.handleResponse;

pjax.handleResponse = function(responseText, request, href, options) {
  if (request.responseText.match("<html")) {
    pjax._handleResponse(responseText, request, href, options);
  } else {
    // handle non-HTML response here
  }
}

refresh([el])

Use this method to bind Pjax to children of a DOM element that didn't exist when Pjax was initialised e.g. content inserted dynamically by another library or script. If called with no arguments, Pjax will parse the entire document again to look for newly-inserted elements.

javascript
// Inside a callback or Promise that runs after new DOM content has been inserted
var newContent = document.querySelector(".new-content");

pjax.refresh(newContent);

reload()

A helper shortcut for window.location.reload(). Used to force a page reload.

javascript
pjax.reload()

Options

elements (String, default: "a[href], form[action]")

CSS selector(s) used to find links to apply Pjax to. If needing multiple specific selectors, separate them by a comma.

javascript
// Single element
var pjax = new Pjax({
  elements: ".ajax"
})
javascript
// Multiple elements
var pjax = new Pjax({
  elements: ".pjax, .ajax",
})

selectors (Array, default: ["title", ".js-Pjax"])

CSS selectors used to find which content to replace.

javascript
var pjax = new Pjax({
  selectors: [
    "title",
    "the-content",
  ]
})

If a query returns multiples items, it will just keep the index.

Example of what you can do:

xml
<!DOCTYPE html>
<html>
<head>
  <title>Page title</title>
</head>
<body>
  <header class="js-Pjax">...</header>
  <section class="js-Pjax">...</section>
  <footer class="the-footer">...</footer>
  <script>...</script>
</body>
</html>

This example is correct and should work "as expected".

NOTE: If the current page and new page do not have the same amount of DOM elements, Pjax will fall back to normal page load.

switches (Object, default: {})

This is an object containing callbacks that can be used to switch old elements with new elements.

The object keys should be one of the defined selectors (from the selectors option).

Examples:

javascript
var pjax = new Pjax({
  selectors: ["title", ".Navbar", ".js-Pjax"],
  switches: {
    "title": Pjax.switches.outerHTML, // default behavior
    ".the-content": function(oldEl, newEl, options) {
      // this is identical to the default behavior
      oldEl.outerHTML = newEl.outerHTML
      this.onSwitch()
    },
    ".js-Pjax": Pjax.switches.sideBySide
  }
})

Callbacks are bound to the Pjax instance itself to allow you to reuse it (ex: this.onSwitch())

Existing Switch Callbacks

  • Pjax.switches.outerHTML: The default behavior, replaces elements using outerHTML.
  • Pjax.switches.innerHTML: Replaces elements using innerHTML and copies className.
  • Pjax.switches.replaceNode: Replaces elements using replaceChild
  • Pjax.switches.sideBySide: Smart replacing that allows you to have both elements in the same parent when you want to use CSS animations. Old elements are removed when all children have been fully animated (an animationEnd event is triggered).

Creating a Switch Callback

Your callback function can do whatever you want, but you need to:

  1. Replace the oldEl's content with the newEl's content in some fashion.
  2. Call this.onSwitch() to trigger the attached callback.

Here is the default behavior as an example:

javascript
function(oldEl, newEl, pjaxOptions) {
  oldEl.outerHTML = newEl.outerHTML
  this.onSwitch()
}

switchesOptions (Object, default: {})

These are options that can be used during content replacement by switches. For now, only Pjax.switches.sideBySide uses it. This is very convenient when you use something like Animate.css with or without WOW.js.

…

Note that remove includes Animated--reverse which is a simple way to not have to have a duplicate transition (slideIn + reverse => slideOut).

Here is some css that works well with the above configuration:

…

To give context to this CSS, here is an HTML snippet:

xml
<!doctype html>
<html>
<head>
  <title>Page Title</title>
</head>
<body>
  <section class="js-Pjax">
    

    
  </section>
  <script>...</script>
</body>
</html>

history (Boolean, default: `true

Issues· 39 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

JavaScriptajaxjquery-pjaxnavigationpjax

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言