raw Software

jQuery Paging

Robert Eisele

jQuery Paging is a small, callback-driven pagination library. It calculates page ranges and navigation states but deliberately leaves the markup, content loading, and visual design to the application. The same core can therefore paginate an in-memory list, drive an Ajax endpoint, render page links, or control a table without imposing a fixed DOM structure.

Get jQuery Paging on GitHub

Its compact format language controls which navigation elements are calculated. An onFormat callback turns each calculated element into application-specific HTML, while onSelect receives the exact slice bounds for the selected page. This separation is the useful part of the design: pagination arithmetic stays in one place, and presentation remains under local control.

Pagination Workbench

Change the data size, page width, overlap, or format string. The list shows the half-open slice selected by the plugin, and the navigation itself is generated through onFormat.

    Installation and Basic Use

    Load jQuery first and then the browser build:

    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
    <script src="jquery.paging.min.js"></script>

    Calling paging(number, options) on one or more containers creates the navigation and returns a controller. The plugin does not ship a required stylesheet or content template.

    const pager = $('#pagination').paging(1337, {
      format: '[< nncnn! >]',
      perpage: 10,
      page: 1,
      onSelect: function (page) {
        console.log(page, this.slice);
        return false;
      },
      onFormat: formatPage
    });

    The Range Calculation

    Let N be the number of items, P the number per page, and L the overlap between consecutive pages, with 0 <= L < P. The effective step is P - L. jQuery Paging computes the number of pages as follows:

    pages = 1 + Math.ceil((N - P) / (P - L));

    For one-based page p, the callback receives a JavaScript-compatible half-open interval [start, end):

    start = (p - 1) * (P - L);
    end = Math.min(start + P, N);

    The bounds can be passed directly to Array.prototype.slice(). If P = 10 and L = 2, the first slices are [0, 10), [8, 18), and [16, 26). The plugin reduces an overlap greater than or equal to the page width to P - 1, preventing a zero step.

    Format Language

    The format string controls which element types are sent to onFormat. Whitespace and other unknown characters are ignored; they are useful only for making the format readable.

    TokenCallback type and meaning
    n and cA page-number block. Its width is the token length; c fixes the current page's preferred position.
    *A block containing every page.
    < and >prev and next controls.
    [ and ]first and last controls.
    q and pleft and right page shortcuts outside the central block.
    - and .Application-defined fill and leap elements.
    (...)A visibility group: its members are active or inactive together.
    !After a number block, preserves its full width with inactive positions near the ends.

    For example, [< (q-) nncnn! (-p) >] requests first, previous, one left shortcut, a separator, five central page positions, a right separator and shortcut, next, and last. Formatting remains entirely in the callback.

    Formatting Callback

    onFormat(type) runs once per calculated navigation element. Its this object always includes number, lapping, pages, perpage, page, and slice. Depending on the token, it also provides value, pos, active, first, and last.

    function formatPage(type) {
      if (type === 'block') {
        if (!this.active) return '<span>' + this.value + '</span>';
        if (this.value === this.page) {
          return '<span aria-current="page">' + this.value + '</span>';
        }
        return '<a href="#page-' + this.value + '">' + this.value + '</a>';
      }
    
      if (type === 'prev' || type === 'next') {
        const label = type === 'prev' ? 'Previous' : 'Next';
        return this.active
          ? '<a href="#page-' + this.value + '">' + label + '</a>'
          : '<span>' + label + '</span>';
      }
    
      return '';
    }

    Returned strings are inserted with jQuery's html(). Treat the callback as an HTML-producing boundary: escape or reject untrusted labels instead of interpolating user-controlled strings directly.

    Selection Callback

    onSelect(page) runs after initialization and after a page change. Its context contains number, lapping, pages, and slice. Returning true allows the clicked link's destination to be followed; returning false keeps navigation inside the callback.

    let previous = [0, 0];
    const rows = $('.result-row');
    
    function selectPage(page) {
      rows.slice(previous[0], previous[1]).hide();
      rows.slice(this.slice[0], this.slice[1]).show();
      previous = this.slice;
      return false;
    }

    An Ajax-backed implementation can use the same precomputed bounds without duplicating pagination arithmetic:

    function selectPage(page) {
      $.ajax({
        url: '/records',
        data: {
          start: this.slice[0],
          end: this.slice[1],
          page: page
        },
        success: renderRows
      });
      return false;
    }

    Options

    OptionPurpose
    perpageItems in one page; values below 1 fall back to 10.
    lappingItems shared by consecutive slices; defaults to 0.
    pageInitial page. Negative values count from the end; null postpones initial selection.
    formatToken string that defines the calculated navigation structure.
    stepwidthPages moved by previous and next. Zero selects block-wise movement.
    circularWraps previous and next around finite page ranges.
    lockDisables page changes and calls onSelect with page 0 when invoked.
    refreshObject with url and interval in seconds for periodic data checks.
    onFormatProduces HTML for each calculated navigation element.
    onSelectConsumes the selected page and slice bounds.
    onClickReplaces the built-in click handling; the application must call setPage().
    onRefreshReceives data returned by the periodic refresh request.

    Controller Methods

    setPage(page), setNumber(number), and setOptions(options) all return the controller, so updates can be chained. Calling setPage() without an argument redraws the configured page. A negative item count creates an endless paginator: there is no known last page, first/last behavior changes accordingly, and an all-pages * block is not meaningful.

    pager
      .setOptions({ perpage: 25, circular: true })
      .setNumber(845)
      .setPage(1);

    The browser build uses the classic jQuery plugin API and is compatible with the jQuery 3.6.4 runtime loaded by this page. Applications targeting a different jQuery major version should run their own integration tests, especially if they use the optional refresh path.