Sortable
Vanilla JavaScript table sort
Install / Use
/learn @tofsjonas/SortableREADME
Makes any table with class="sortable", er, sortable. The user can click on a table header and change the sorting of the table rows.
Just include the JavaScript and it will work. No function calls are needed, everything is handled by a JavaScript HTML DOM EventListener.
<h2>Related Projects</h2>🔍 searchable - A companion library that makes tables searchable/filterable, perfect to use alongside sortable!
<h2>Demo</h2>You can find a simple demo on https://tofsjonas.github.io/sortable/
<h2>Table of Contents</h2> <!-- TOC -->- Factoids
- "Installation"
- Flavours/Versions
- Non-sortable field
- Indicators/arrows on the left side
- NOTE ABOUT CSS/SCSS
- Sorting sizes, dates and such
- Alternative sorting
- Colspans/Sort on specific column
- Concerning rowspan
- Ascending sort
- Tiebreaker / secondary sort
- Empty/null rows always last
- Accessibility
- Sort Events
- Sort on load
- Thank you...
Factoids
-
1.71K minified. (899 bytes gzipped)
-
Works with JavaScript generated tables. (since we are using an eventListener)
-
Lightning fast. Huge tables will make it slow and may freeze the browser, especially for mobiles, so you know...
-
Requires thead and tbody.
-
rowspan is not supported 😢
-
NOT tested with React, Angular, Vue, etc.
-
Works with Svelte!
"Installation"
There are three ways to use sortable, all of which have their pros and cons. S Anand and dkhgh had some interesting thoughts about it.
link to jsDelivr
<table class="sortable">
<thead>
<tr>
<th><span>Role</span></th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>Genius</td>
<td>Rick</td>
</tr>
<tr>
<td><a href="javascript:alert('standalone javascript works!');">Sidekick</a></td>
<td>Morty</td>
</tr>
</tbody>
</table>
<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/dist/sortable.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/dist/sortable.min.js"></script>
<!-- OR: -->
<script src="https://cdn.jsdelivr.net/gh/tofsjonas/sortable@latest/dist/sortable.auto.min.js"></script>
The span on line four is just there to prove that you can have elements inside th!
⚠️ If you are concerned about bugs, I recommend using version numbers instead of "latest".
copy file to assets folder
Same as above, but link to your own files from the dist directory
...
<link href="/assets/sortable.min.css" rel="stylesheet" />
<script src="/assets/sortable.min.js"></script>
<!-- OR: -->
<script src="/assets/sortable.auto.min.js"></script>
...
npm package
First,
npm install sortable-tablesort
# yarn add sortable-tablesort
# pnpm install sortable-tablesort
Now you can:
a) use links in the html
Same as above, with links to files from the dist directory
...
<link href="./node_modules/sortable-tablesort/dist/sortable.min.css" rel="stylesheet" />
<script src="./node_modules/sortable-tablesort/dist/sortable.min.js"></script>
<!-- OR: -->
<script src="./node_modules/sortable-tablesort/dist/sortable.auto.min.js"></script>
...
or
b) import files in javascript
// main.js
import 'sortable-tablesort/dist/sortable.min.css'
import 'sortable-tablesort/dist/sortable.min.js'
// OR
import 'sortable-tablesort/dist/sortable.auto.min.js'
Flavours/Versions
There are two flavours, Lightweight (default) and Full-Featured (Automatic)
Lightweight - default
Lightweight is the old-school sortable with an eventListener only, where you can add the a11y package if you want. This is probably the one you are looking for.
<script src="sortable.js"></script>
<!-- Optional: -->
<script src="sortable.a11y.js"></script>
Full-Featured - automatic
This one includes accessibility, auto-initialization, mutation observer, and automatic sorting on load.
- Auto-sort on load: Add
aria-sort="ascending"oraria-sort="descending"to anythto sort that column when the page loads - Auto-initialization: Automatically finds and initializes all
.sortabletables on page load - Mutation observer: Automatically initializes new
.sortabletables added to the HTML DOM after page load
Note: This version already includes all accessibility features - no need to load sortable.a11y.js separately.
<script src="sortable.auto.js"></script>
⚠️ The file is a bit bigger (2.72K minified / 1.22K gzipped) since there is more code, and the mutation observer triggers every time there is a change to the DOM. So if you are using React or some other library that affects the DOM a lot (it is not tested with React or any other DOM heavy libs), please be careful.
Performance note: The mutation observer watches for all DOM changes. If your application frequently modifies the DOM (e.g., real-time updates, animations), this could impact performance. Consider using the lightweight version if you:
- Have tables that update their content frequently
- Use frameworks that perform many DOM updates
- Don't need automatic initialization of dynamically added tables
Test it out
<script src="sortable.auto.js"></script>
<script>
const table = document.createElement('table')
table.classList.add('sortable')
table.innerHTML = `
<thead>
<tr>
<th data-sort="name" aria-sort="ascending">Name</th>
<th data-sort="age">Age</th>
</tr>
</thead>
<tbody>
<tr><td>John Doe</td><td>30</td></tr>
<tr><td>Jane Smith</td><td>25</td></tr>
</tbody>
`
setTimeout(() => {
document.body.appendChild(table)
}, 600) // Delay so you can see the table being added
</script>
Mutation Observer and Nested Tables
Note that the observer only triggers when you add tables directly to the DOM! If you wrap the table in a div for instance, you need to make sure that the div is added to the DOM before the table is.
const div = document.createElement('div')
// This will NOT trigger the mutation observer
div.appendChild(table) // adds the table to a div that is not part of the DOM
document.body.appendChild(div) // Now the DIV is added to the dom, not the table
// This WILL trigger the mutation observer
document.body.appendChild(div) // the div is added to the DOM, becoming part of the DOM
div.appendChild(table) // the table is added to the DOM
Which (minimised) Version Should I Use?
| Feature | sortable.js | sortable.js + sortable.a11y.js | sortable.auto.js | | ------------------- | -------------------- | ------------------------------ | --------------------- | | Basic sorting | ✓ | ✓ | ✓ | | Size | 1.71K (899B gzipped) | ~2.7K combined | 3.04K (1.36K gzipped) | | Accessibility | ✗ | ✓ | ✓ | | Auto-initialization | ✗ | ✗ | ✓ | | Mutation observer | ✗ | ✗ | ✓ | | Auto-sort on load | ✗ | ✗ | ✓ | | Performance impact | Minimal | Minimal | Moderate* |
*Due to mutation observer watching DOM changes
Non-sortable field
using class="no-sort"
If you wish to disable sorting for a specific field, the easiest (and best) way is to add class="no-sort" to it, like so:
<thead>
<tr>
<th class="no-sort">Role</th>
<th>Name</th>
</tr>
</thead>
Sorti
