Skip to content

Sortable Markdown Tables: GitHub, GitLab, MkDocs and R Markdown

By MarkdownTables.com editorial teamUpdated

On this page

Can a Markdown table be sortable?

A Markdown pipe table describes rows and columns and nothing else. The Markdown table syntax has no flag for “sortable”, so a clickable header can only come from the place where the table is displayed: a feature of the renderer, or JavaScript on the page. That is why the answer differs by platform.

A table in source order
Markdown
| Library   | Stars | Released |
| :-------- | ----: | :------- |
| Alpha     |   420 | 2021     |
| Bravo     |  1310 | 2019     |
| Charlie   |    85 | 2024     |
| Delta     |   960 | 2022     |
Preview
LibraryStarsReleased
Alpha4202021
Bravo13102019
Charlie852024
Delta9602022

On GitHub the headers can’t be clicked. To put the rows in order there, sort the source (below).

Open in editor : A table in source order

You have two broad choices: make the displayed table sortable on a platform that can do it, or sort the rows in the Markdown before you publish. The second works everywhere, including Reddit and chat tools.

Every way to get a sortable table, by platform

How to get a sortable table
WhereMethodSetup
GitHub README, issues, wikisSort the source rowsUse the table sorter or a spreadsheet
GitLabSortable tables, json:table with sortable fieldsBuilt in
MkDocs Materialtablesort scriptextra_javascript plus a short JS file
Docusaurus, Hugo, Jekyll, custom sitesA JavaScript sort library or your own scriptLoad a script, run it on table elements
R Markdown, Quarto (HTML)DT::datatable(), reactable::reactable()Install the package
Jupyteritables.show(df) or pandas sortingInstall itables
ObsidianDataview SORT, Bases, Advanced TablesPlugin or core plugin setup
Anywhere with a spreadsheetSort the data, then convert to MarkdownCSV to Markdown table

GitHub: no sorting, so sort the source

GitHub renders Markdown tables as static HTML and removes scripts, so a README table can't be sorted by the reader. A table you want in a specific order has to be in that order in the file. Sort by the column that readers care about, say stars, newest first, or alphabetical, and note the order in the sentence above the table.

The same data sorted by Stars, descending
Markdown
| Library   | Stars | Released |
| :-------- | ----: | :------- |
| Bravo     |  1310 | 2019     |
| Delta     |   960 | 2022     |
| Alpha     |   420 | 2021     |
| Charlie   |    85 | 2024     |
Preview
LibraryStarsReleased
Bravo13102019
Delta9602022
Alpha4202021
Charlie852024

The Markdown table sorter does this in the browser: paste the table, click a column header in the grid (once for ascending, twice for descending), and copy the Markdown. It detects numeric columns, so 2 sorts before 10, and the header and delimiter rows stay in place. For a script in CI or a local workflow, sorting the body rows from the shell also works:

Sort the data rows by the second column, numericallyShell
# Keep the header and delimiter rows, sort the data rows by column 2, descending
(head -n 2 table.md; tail -n +3 table.md | sort -t '|' -k3,3nr) > sorted.md

This works only on tables whose cells contain no pipes. Cells containing \| split in the wrong place, and values such as 1,310 don't sort numerically with sort -n. Use the tool for tables with that kind of data. See the GitHub README tables guide for more on what renders there.

GitLab: sortable tables and json:table

GitLab renders sortable tables, and its json:table code block builds one from JSON. Mark each field that should sort with sortable: true; a top-level filter adds a search box. The GitLab Flavored Markdown docs list the full set of options, which can change between versions.

A sortable table with json:table (GitLab)Markdown
```json:table
{
  "fields": [
    { "key": "library", "label": "Library", "sortable": true },
    { "key": "stars", "label": "Stars", "sortable": true },
    { "key": "released", "label": "Released", "sortable": true }
  ],
  "items": [
    { "library": "Alpha", "stars": 420, "released": 2021 },
    { "library": "Bravo", "stars": 1310, "released": 2019 },
    { "library": "Charlie", "stars": 85, "released": 2024 }
  ],
  "filter": true
}
```

The data lives in JSON rather than pipes, so it is harder to diff and doesn't render on GitHub, where it shows as a code block. For a table that must read well in both places, keep a normal pipe table and sort it in the source. See the GitLab Markdown tables guide.

MkDocs Material: the tablesort recipe

Material for MkDocs documents a recipe that uses the tablesort library. Load the script, then initialize it on every table inside the article. The document$ subscription re-runs the code when instant navigation swaps the page, so sorting keeps working after the first click through the site.

mkdocs.ymlYAML
# mkdocs.yml
extra_javascript:
  - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js
  - javascripts/tablesort.js
docs/javascripts/tablesort.jsJavaScript
// docs/javascripts/tablesort.js
document$.subscribe(function () {
  var tables = document.querySelectorAll("article table:not([class])")
  tables.forEach(function (table) {
    new Tablesort(table)
  })
})

The selector skips tables that have a class, so tables made by other components are left alone. For numbers and dates, add tablesort's number and date extensions; the core library compares text, as its README explains.

Docusaurus, Hugo, Jekyll and other sites

Docusaurus, Hugo, Jekyll and plain HTML pages have no built-in sorting. Two routes work on any of them. Add a library such as tablesort, DataTables or List.js and point it at your tables:

tablesort on every table (any HTML page)HTML
<script src="https://cdn.jsdelivr.net/npm/tablesort@5.3.0/dist/tablesort.min.js"></script>
<script>
  document.querySelectorAll('table').forEach(function (table) {
    new Tablesort(table);
  });
</script>

Or write a short script yourself. This version sorts text and numbers in the clicked column, and toggles between ascending and descending:

Click-to-sort without a libraryJavaScript
document.querySelectorAll('table').forEach(function (table) {
  var body = table.tBodies[0];
  table.querySelectorAll('th').forEach(function (th, col) {
    th.style.cursor = 'pointer';
    th.addEventListener('click', function () {
      var dir = th.dataset.dir === 'asc' ? -1 : 1;
      th.dataset.dir = dir === 1 ? 'asc' : 'desc';
      var text = function (row) { return row.cells[col].textContent.trim(); };
      Array.from(body.rows)
        .sort(function (a, b) {
          return dir * text(a).localeCompare(text(b), undefined, { numeric: true });
        })
        .forEach(function (row) { body.appendChild(row); });
    });
  });
});

Headers made clickable with a plain click handler can't be reached with the keyboard. For a public site, use a library that handles keyboard focus and ARIA sort state, or wrap each header's text in a button. Hugo drops raw HTML, including inline <script>, unless markup.goldmark.renderer.unsafe is on, so load scripts from the theme's templates instead. Docusaurus needs the script in scripts in its config or a React component.

R Markdown, Quarto and Jupyter

R Markdown and Quarto can emit interactive tables when the output is HTML. DT::datatable() and reactable::reactable() sort by clicking a header. knitr::kable() writes a regular Markdown table, which is static.

Sortable tables in an R Markdown HTML documentR Markdown
```{r}
library(DT)
datatable(mtcars)          # sortable, searchable, paged (HTML output)
```

```{r}
library(reactable)
reactable(mtcars)          # sortable by default (HTML output)
```

```{r}
knitr::kable(head(mtcars)) # static Markdown table: not sortable
```

Both packages need JavaScript, so they don't work in PDF or Word output, where a static kable() table is the right choice. In Jupyter, Markdown-cell tables are static. Show a DataFrame with itables to get click-to-sort, or sort with pandas and export Markdown:

Interactive in the notebook, sorted when exportedPython
import pandas as pd
from itables import show

df = pd.read_csv("libraries.csv")
show(df)                       # interactive table with click-to-sort headers
df.sort_values("stars", ascending=False).to_markdown("sorted.md", index=False)

Obsidian: Dataview, Bases and sorting the source

Obsidian renders pipe tables as static HTML. For sorted output, query your notes with the Dataview plugin and put the order in the query; Bases, the core plugin for database-style views, lets you set sorting in the view. The Advanced Tables community plugin sorts the rows of a Markdown table in the editor, which changes the source. See Obsidian and Notion tables.

Dataview: a sorted table from your notesMarkdown
```dataview
TABLE stars, released
FROM "Libraries"
SORT stars DESC
```

Sortable tables by platform

Sortable Markdown tables by platform
PlatformClick to sortWorkaround
GitHub (GFM)Rendered tables are static, and scripts are removed from Markdown.NoYes: Sort the source rows
GitLab (GLFM)Renders sortable tables. json:table blocks set sortable per field. Check GitLab’s docs for which views and versions apply.Yes: json:table fieldsNot applicable
ObsidianPlain Markdown tables are static. Dataview and Bases sort by query or view settings.NoYes: Dataview, Bases, Advanced Tables
VS Code previewStatic HTML table.NoYes: Sort the source
JupyterMarkdown-cell tables are static. Code output can be interactive.NoYes: itables, pandas
R Markdown / Quarto (HTML)DT::datatable() and reactable::reactable() sort in the browser. knitr::kable() output is static.Yes: DT, reactableNot applicable
PandocTables are static. HTML output needs your own JavaScript.NoPartly: JS in HTML output
MkDocs MaterialThe theme documents a tablesort recipe.Yes: tablesort recipeNot applicable
Docusaurus / Hugo / JekyllNo built-in sorting. Load a JavaScript library or write a small script.Partly: Add JSYes: Sort the source
Reddit, Slack, DiscordNo scripting and no sortable table element.NoYes: Sort the source

✅ supported · ⚠️ partly or with a workaround · ❌ not supported · Last verified October 2026

“Sort the source” means reordering the Markdown rows before publishing. It works everywhere but only changes the order for everyone.

Common mistakes (broken vs. fixed)

Numbers sorted as text

Broken: sorted as text, 100 comes before 20 and 3
Markdown
| Library | Stars |
| :------ | ----: |
| Alpha   | 100   |
| Bravo   | 20    |
| Charlie | 3     |
Preview
LibraryStars
Alpha100
Bravo20
Charlie3

A text sort puts 100, 20, 3 in that order. Use a numeric sort (the sorter tool, localeCompare with numeric: true, or tablesort’s number extension).

A script in a README

Broken on GitHub: the script is removedMarkdown
| Library | Stars |
| ------- | ----: |
| Alpha   | 420   |

<script src="https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js"></script>
<script>new Tablesort(document.querySelector('table'))</script>

GitHub strips <script>, so the table stays unsorted and the tags don't appear. Use scripts only on sites you publish yourself.

Sorting a table with merged cells

Script-based sorters move whole rows. A table with rowspan or colspan breaks, because the spanned cell belongs to several rows. Keep sortable tables flat; the nested tables page shows flat alternatives to grouped layouts.

Formatted values

Cells like $1,200, 2 MB or 12 Jan sort in surprising ways. Either keep the column in a sortable format (numbers without units, ISO dates such as 2026-10-11) and put the unit in the header, or use a library that reads a separate sort key.

When to use a database table or spreadsheet

  • The table is data readers will filter and sort. Publish it as a page with DataTables, reactable or itables, and link to it from the README.
  • The data lives in a spreadsheet. Share the sheet or a CSV file, and keep a sorted Markdown snapshot with the CSV to Markdown table converter.
  • The table is a short reference. Sort it once by the most useful column and add a sentence that says how it is ordered.
  • The table is long. Hide it in a collapsible section or split it into smaller tables.

Frequently asked questions

Can you make a Markdown table sortable?

Not in the Markdown itself: pipe tables are static data. Sorting comes from the renderer or from JavaScript added to the page. GitLab and MkDocs Material (with a recipe) offer click-to-sort, GitHub does not, and you can always sort the rows in the source.

Is there a sortable table in GitHub Markdown?

No. GitHub renders tables as static HTML and removes scripts, so headers can’t be clicked to sort. Sort the rows before you commit, with the Markdown table sorter or a spreadsheet, or link to a published page that has a sortable table.

Does GitLab support sortable Markdown tables?

Yes: GitLab renders sortable tables, and json:table code blocks define fields with "sortable": true for click-to-sort headers. Check the GitLab Flavored Markdown docs for the options in your version and where they render.

How do I make a sortable table in MkDocs?

Follow the Material for MkDocs recipe: add the tablesort script and a small tablesort.js to extra_javascript in mkdocs.yml, then call new Tablesort(table) on each table. Include tables as plain Markdown; no per-table setup is needed.

How do I make a sortable table in R Markdown?

Use DT::datatable(df) or reactable::reactable(df) in a code chunk with HTML output; both sort by clicking a column header. knitr::kable() produces a plain Markdown table, which is static, and neither package works in PDF or Word output.

Can Obsidian sort a Markdown table?

Plain Markdown tables in Obsidian aren’t sortable in the rendered view. The Dataview plugin sorts with a SORT clause in the query, Bases is built for sortable database views, and the Advanced Tables plugin can sort the rows of a Markdown table in the source.

How do I sort a Markdown table by column?

Paste it into the Markdown table sorter, click a column header, and copy the result. You can also sort the data in a spreadsheet and convert it back with the CSV to Markdown table tool. Keep the header and delimiter rows in place.