<style>
@import url('https://fonts.googleapis.com/css?family=Roboto:400,400i,500,500i,700');
body {
font-family: Roboto;
}
table {
border-collapse: collapse
}
td,
th {
border: 2px solid red;
width: 150px;
height: 40px;
text-align: center;
}
th {
cursor: pointer;
user-select: none;
}
th.sorted[data-order="-1"]::after {
content: "▼"
}
th.sorted[data-order="1"]::after {
content: "▲"
}
</style>
<table>
<thead onclick="getSort(event)">
<tr>
<th>Name</th>
<th>SecondName</th>
<th>Patronymic</th>
<th>Age</th>
</tr>
</thead>
<tbody contenteditable>
<tr>
<td>Макс</td>
<td>Троцкий</td>
<td>Ильич</td>
<td>77</td>
</tr>
<tr>
<td>Вася</td>
<td>Петров</td>
<td>Александрович</td>
<td>21</td>
</tr>
<tr>
<td>Петя</td>
<td>Иванов</td>
<td>Петрович</td>
<td>15</td>
</tr>
<tr>
<td>Миша</td>
<td>Ложкин</td>
<td>Васильевич</td>
<td>43</td>
</tr>
<tr>
<td>Владимир</td>
<td>Сидоров</td>
<td>Игоревич</td>
<td>33</td>
</tr>
<tr>
<td>Коля</td>
<td>Колбаскин</td>
<td>Олегович</td>
<td>41</td>
</tr>
</tbody>
</table>
<script>
const getSort = ({target}) => {
const order = target.dataset.order = -target.dataset.order || 1;
const index = [...target.parentNode.cells].indexOf(target);
const collator = new Intl.Collator(["en", "ru"], {numeric: true});
const comparator = (index, order) => (a, b) => order * collator.compare(a.children[index].innerHTML, b.children[index].innerHTML);
for (const tBody of target.closest("table").tBodies) tBody.append(...[...tBody.rows].sort(comparator(index, order)));
for (const cell of target.parentNode.cells) cell.classList.toggle("sorted", cell === target);
};
</script>
еще пример