SkillAgentSearch skills...

Sortable

Vanilla JavaScript table sort

Install / Use

/learn @tofsjonas/Sortable

README

<!-- markdownlint-disable MD033 MD026 --> <h1>sortable</h1> <h5>- a tiny, vanilla/plain JavaScript table sorter</h5>

GitHub Issues or Pull Requests NPM Version NPM Downloads GitHub Repo stars jsdelivr

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 --> <!-- /TOC -->

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" or aria-sort="descending" to any th to sort that column when the page loads
  • Auto-initialization: Automatically finds and initializes all .sortable tables on page load
  • Mutation observer: Automatically initializes new .sortable tables 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

View on GitHub
GitHub Stars496
CategoryDevelopment
Updated9d ago
Forks47

Languages

TypeScript

Security Score

100/100

Audited on Mar 16, 2026

No findings