JSFiddle - React, Tailwind, and code Playground

by nhoizey

HTML

<ul id="paginate">
    <li><strong data-href="page-1">1</strong></li>
    <li><a href="page-2">2</a></li>
    <li><a href="page-3">3</a></li>
    <li><a href="page-4">4</a></li>
    <li><a href="page-5">5</a></li>
</ul>
<div id="results">
    <ul><li>#1</li><li>#2</li><li>#3</li><li>#4</li><li>#5</li><li>#6</li><li>#7</li><li>#8</li><li>#9</li><li>#10</li></ul>
</div>

CSS

#paginate li {
    display: inline-block;
}

#paginate li+li::before {
    content: "|";
    display: inline-block;
    margin: 0 0.5em;
}

#paginate .active {
    font-weight: bold;
}

#results {
    width: 25em;
    position: relative;
}

#results .throbber {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    line-height: 3em;
    background-color: rgba(255, 255, 255, 0.75);
    color: green;
    text-align: center;
}

#results li {
    display: block;
    float: left;
    width: 2em;
    height: 2em;
    background-color: #ccc;
    color: #999;
    font-size: 3em;
    text-align: center;
    line-height: 2.15em;
    font-weight: bold;
    text-shadow: -1px -1px 0 #777, 1px 1px 0 #eee;
    margin: 0 0.15em 0.15em 0;
}

JavaScript

// Pagination over pushState and history API
// =========================================
//
// This file describes howto implement a paginate navigation throught the
// history API using pushState / popState stateObjects to store and retrieve
// the backend content.
//
// We use backend content formated as HTML for demo purposes, but we can
// safetly use any type of content as this one is parsed before the DOM
// rendering.
//

// Paginate
// --------
//
// We build a Paginate object that'll manage the pagination list. It's
// responsible of links triggering and visual changes.
//
var Paginate = function Paginate(selector) {
    this.$el = $(selector);
    this.bindEvents();
    $(document).trigger('search:init', this.$el.find('strong').data('href'));
};

// Paginate deals with 2 events:
// 
// - click on a link : trigger a new request to backend
// - results update : update current pagination link to a `<strong>` element
//
Paginate.prototype.bindEvents = function PaginateBindEvents() {
    this.$el.on('click', 'a', $.proxy(this.getResults, this));
    $(document).on('results:update', $.proxy(function (e, data, token) {
        this.setActive(token);
    }, this));
};

// Trigger the request by using jQuery as a mediator interface between our
// objects. We pass the currently clicked `href` as a request param.
//
Paginate.prototype.getResults = function PaginateGetResults(e) {
    e.preventDefault();
    
    var url = $(e.target).attr('href');
    $(document).trigger('search:get', [url]);
};

// Switch the current item and the new item with tag replacement.
//
Paginate.prototype.setActive = function PaginateSetActive(url) {
    var $current = this.$el.find('strong'),
        $next = this.$el.find('[href="' + url + '"]');
        
    $current
    .after(
        $('<a/>', {
            href: $current.data('href'),
            text: $current.text()
        })
    )
    .remove();
    
    $next
    .after(
        $('<strong/>', {
            'data-href':...