JSFiddle - React, Tailwind, and code Playground

by Igor Schnaider

HTML

<table>
    <thead>
        <tr>
            <th data-sort="string"><span>Имя</span></th>
            <th data-sort="string"><span>Фамилия</span></th>
            <th data-sort="number"><span>Возраст</span></th>
            <th data-sort="string"><span>Женат/Замужем</span></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Элла</td>
            <td>Журавель</td>
            <td>17</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Орест</td>
            <td>Мамедов</td>
            <td>52</td>
            <td>да</td>
        </tr>
        <tr>
            <td>Степан</td>
            <td>Шмидт</td>
            <td>30</td>
            <td>да</td>
        </tr>
        <tr>
            <td>Александр</td>
            <td>Соколов</td>
            <td>48</td>
            <td>да</td>
        </tr>
        <tr>
            <td>Карл</td>
            <td>Дидиченко</td>
            <td>24</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Серафима</td>
            <td>Куколевская</td>
            <td>27</td>
            <td>да</td>
        </tr>
        <tr>
            <td>Сусанна</td>
            <td>Борисова</td>
            <td>28</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Артур</td>
            <td>Баландин</td>
            <td>32</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Мария</td>
            <td>Савельева</td>
            <td>37</td>
            <td>да</td>
        </tr>
        <tr>
            <td>Мария</td>
            <td>Журавель</td>
            <td>34</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Трифон</td>
            <td>Трифонов</td>
            <td>19</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Трифон</td>
            <td>Трифонов</td>
            <td>19</td>
            <td>нет</td>
        </tr>
        <tr>
            <td>Ганна</td>
            <td>Фёдорова</td>
        ...

CSS

table {
    width: 30rem;
}

th, td {
    padding: .5em;
}

th {
    cursor: pointer;
}

th.up span:after {
    content: '↑';
    margin-left: .5em;
}

th.down span:after {
    content: '↓';
    margin-left: .5em;
}

td {
    border: 1px solid;
}

#paginator a {
    margin: 0 .15em;
}

.paginator-wrapper {
    display: inline-block;
}

JavaScript

var table = document.querySelector('table')
    , thead = table.tHead
    , tbody = table.tBodies[0].cloneNode(true)
    , rows = Array.prototype.slice.call( tbody.rows )
    , indexRow
    , targetTH = thead.rows[0].children[0]
    , selectVal = document.getElementsByTagName('select')[0].value
    , currentPage = 1
    , _high
    , _pointer
;

thead.onclick = function(e) {
    var target = e.target;

    // If there are other elements within TH
    while (target !== this) {
        if (target.tagName === 'TH') {
            break;
        }

        target = target.parentNode;
    }

    _assembleTable(target);
};


function _sortTable(target) {
    if (sortType = target.getAttribute('data-sort')) {
        if (indexRow === target.cellIndex) {
            _reverse();
        } else {
            indexRow = target.cellIndex;

            if (sortType === 'string') {
                _sortAsc(indexRow);
            }

            if (sortType === 'number') {
                _sortNum(indexRow);
            }
        }
    }
}

function _sortAsc(index) {
    rows.sort(function (a, b) {
        return a.cells[index].textContent > b.cells[index].textContent;
    });
}

function _sortNum(index) {
    rows.sort(function (a, b) {
        return a.cells[index].textContent - b.cells[index].textContent;
    });
}

function _reverse() {
    rows.reverse();
}

function _changeTableView(target) {
    _changeTableBody();
    _changeTableHead(target);
}

function _changeTableBody() {
    table.removeChild( table.tBodies[0] );

    // Assembling the new TBODY
    var _tbody = document.createElement('tbody')
        , _row
    ;

/*
    for (var i = 0, l = rows.length; i < l; i++) {
        _tbody.appendChild( rows[i] );
    }
*/

    // Display only required amount of rows
    _pointer = (currentPage - 1) * selectVal;
    _high = currentPage * selectVal;

    while ( tbody.rows[_pointer] && _pointer < _high ) {
        _row = rows[_pointer].cloneNode(true);
       ...