Flexible Client-Side Table Sorting Plugin - tablesorter

File Size: 2 MB
Views Total: 21941
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
Flexible Client-Side Table Sorting Plugin - tablesorter

tablesorter is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes and any server-side code.  

tablesorter can successfully parse and sort many types of data including linked data in a cell.

You may also like:


  • Multi-column sorting
  • Parsers for sorting text, URIs, integers, currency, floats, IP addresses, dates (ISO, long and short formats), time. Add your own easily
  • Support secondary "hidden" sorting (e.g., maintain alphabetical sort when sorting on other criteria)
  • Extensibility via widget system
  • Compatible with Bootstrap and jQuery UI frameworks
  • 15 built-in themes
  • Tons of configs, API methods and event handlers

Basic Usage:

1. Include the latest jquery library and other necessary javascript files.

<!-- Required -->
<script src="/path/to/cdn/jquery.min.js"></script>
<script src="/path/to/js/jquery.tablesorter.min.js"></script>
<!-- Optional Widgets -->
<script src="/path/to/js/jquery.tablesorter.widgets.min.js"></script>

2. Include a Theme CSS on the page.

  1. theme.black-ice.css
  2. theme.blue.css
  3. theme.bootstrap.css
  4. theme.bootstrap_2.css
  5. theme.bootstrap_3.css
  6. theme.bootstrap_4.css
  7. theme.dark.css
  8. theme.default.css
  9. theme.dropbox.css
  10. theme.green.css
  11. theme.grey.css
  12. theme.ice.css
  13. theme.jui.css
  14. theme.materialize.css
  15. theme.metro-dark.css
<link href="css/theme.default.css" rel="stylesheet">

3. Create an HTML table to be sortable.

<table class="tablesorter">
      <td>abc 123</td>
      <td>abc 1</td>
      <td>abc 9</td>
      <td>zyx 24</td>
      <td>abc 11</td>
      <td>abc 2</td>
      <td>abc 9</td>
      <td>ABC 10</td>
      <td>zyx 1</td>
      <td>zyx 12</td>

4. Call the plugin on the HTML table and enable the Sortable functionality.

    // options here

5. All default configuration options.

// adds tablesorter-{theme} to the table for styling
theme            : 'default',  

// adds colgroup to fix widths of columns
widthFixed       : false,      

// show an indeterminate timer icon in the header when the table is sorted or filtered.
showProcessing   : false,      

// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> 
headerTemplate   : '{content}',

// function( index, template ) { return template; }
onRenderTemplate : null,       

// function( index ) {}
onRenderHeader   : null,       

// prevent text selection in the header
cancelSelection  : true,       

// add tabindex to header for keyboard accessibility
tabIndex         : true,       

// other options: 'ddmmyyy' or 'yyyymmdd'
dateFormat       : 'mmddyyyy', 

// key used to select additional columns
sortMultiSortKey : 'shiftKey', 

// key used to remove sorting on a column
sortResetKey     : 'ctrlKey',  

// false for German '1.234.567,89' or French '1 234 567,89'
usNumberFormat   : true,       

// if false, the parsed table contents will not update until the first sort
delayInit        : false,      

// if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
serverSideSorting: false,      

// default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
resort           : true,       

// set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
headers          : {},         

// ignore case while sorting
ignoreCase       : true,       

// column(s) first sorted; always applied
sortForce        : null,       

// Initial sort order; applied initially; updated when manually sorted
sortList         : [],         

// column(s) sorted last; always applied
sortAppend       : null,      

// when sorting two rows with exactly the same content, the original sort order is maintained 
sortStable       : false,      

// sort direction on first click
sortInitialOrder : 'asc',      

// replace equivalent character (accented characters)
sortLocaleCompare: false,      

// third click on the header will reset column to default - unsorted
sortReset        : false,      

// restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
sortRestart      : false,      

// sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
emptyTo          : 'bottom',   

// sort strings in numerical column as max, min, top, bottom, zero
stringTo         : 'max',      

// colspan cells in the tbody will have duplicated content in the cache for each spanned column
duplicateSpan    : true,       

// text extraction method/function - function( node, table, cellIndex ) {}
textExtraction   : 'basic',    

// data-attribute that contains alternate cell text (used in default textExtraction function)
textAttribute    : 'data-text',

// choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
textSorter       : null,       

// choose overall numeric sorter function( a, b, direction, maxColumnValue )
numberSorter     : null,       

// apply widgets on tablesorter initialization
initWidgets      : true,       

// table class name template to match to include a widget
widgetClass      : 'widget-{name}', 

// method to add widgets, e.g. widgets: ['zebra']
widgets          : [],     

// zebra widget alternating row class names    
widgetOptions    : {
  zebra : [ 'even', 'odd' ]  

// // function( table ) {},
initialized      : null,       

// *** extra css class names
tableClass       : '',
cssAsc           : '',
cssDesc          : '',
cssNone          : '',
cssHeader        : '',
cssHeaderRow     : '',
cssProcessing    : '', 

// class name indiciating that a row is to be attached to its parent
cssChildRow      : 'tablesorter-childRow', 

// don't sort tbody with this class name (only one class name allowed here!)
cssInfoBlock     : 'tablesorter-infoOnly', 

// class name added to element inside header; clicking on it won't cause a sort
cssNoSort        : 'tablesorter-noSort',   

// header row to ignore; cells within this row will not be added to c.$headers
cssIgnoreRow     : 'tablesorter-ignoreRow',

// if this class does not exist, the {icon} will not be added from the headerTemplate
cssIcon          : 'tablesorter-icon', 

// class name added to the icon when there is no column sort
cssIconNone      : '', 

// class name added to the icon when the column has an ascending sort
cssIconAsc       : '', 

// class name added to the icon when the column has a descending sort
cssIconDesc      : '', 

// class name added to the icon when the column has a disabled sort
cssIconDisabled  : '', 

// events
pointerClick     : 'click',
pointerDown      : 'mousedown',
pointerUp        : 'mouseup',

// selectors
selectorHeaders  : '> thead th, > thead td',
selectorSort     : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
selectorRemove   : '.remove-me',

// debug mode
debug            : false,

// Internal variables
headerList: [],
empties: {},
strings: {},
parsers: [],

// parser options for validator; values must be falsy!
globalize: 0,
imgAttr: 0

6. Widgets, API, and events are available here.


v2.31.3 (2020-03-04)

  • Cache parsed value in colspan.
  • Restore first row in cacheIndex. 

v2.31.2 (2019-12-02)

  • Fix scroller widget compatibility. 
  • Update select2 regexp.
  • Prevent search on enter if filters are unchanged. 
  • Add math ignore to cells.

v2.31.1 (2019-12-01)

  • Store sortList on init. 
  • Add math_textAttr. 

v2.31.1 (2018-11-21)

  • Store sortList on init. 
  • Add math_textAttr. 

v2.31.0 (2018-08-28)

  • Add nbsp to empty cells.
  • Change default ajaxProcessing function. 
  • Update build to UMD wrap widgets, parsers & extras (necessitates a minor version bump).

v2.30.7 (2018-07-10)

  • Core: Add data-sortedBy to headers; see config.sortVars.
  • Core: Ensure sort parameters are defined. 
  • Parser: input-select updates extra header checkboxes. Fixes issue #1560.
  • CSS: Style caption per table theme. 

v2.30.6 (2018-06-17)

  • CssStickyHeaders: Reinitialize after update. 
  • Parser: Prevent input-select error. 
  • DOC updated.

v2.30.5 (2018-05-29)

  • Ignore clicks on disabled colspan headers. 
  • Add column index & parsed content to formatContent data parameter. 

v2.30.4 (2018-05-17)

  • Core: Use table cell, not jQuery object to disable sort; Fixes issue introduced in v2.30.2.
  • Scroller: Set scrollLeft position after sort.
  • Docs: Add when not to use headers. 

v2.30.3 (2018-05-01)

  • Use indexed headers. 

v2.30.2 (2018-04-27)

  • Allow passing headers from multiple rows. 
  • Use local $ inside of IIFE. 
  • Adjust handle position for jQuery v3.3.0+. Fixes issue #1544.
  • Fix border css for last row.
  • Input-select: Fix TypeError hasSticky is undefined. See issue #1534 & PR #1535; thanks @adamz01h.
  • Update dependencies.

v2.30.1 (2018-03-19)

  • Only validate options while debugging.
  • Pager: Show all rows, not pages.
  • SaveSort: Fix JS error. 

v2.30.0 (2018-03-19)

  • Debug now allows you to debug components separately; set to true as usual, or set to 'core filter' to only show the core and filter widget debug logs.
  • Change pager removeRows check. 
  • Make onlyAvail work with showProcessing. Fixes issue #1518.
  • Escape quotes in select options.
  • Change pager removeRows check.
  • Add editor eslint & fix issues.
  • DOC Updated.

v2.29.6 (2018-02-26)

  • Don't save 'auto' table width. 
  • Adjust spacing for jQuery UI themes.
  • Allow nested tables in sticky header. 
  • Include nested tables inside a scrolling element. 

v2.29.5 (2018-01-31)

  • Clean up language settings & allow empty strings.
  • Fix linting issue.
  • Fix version numbering.
  • Add radio parser. 

v2.29.4 (2018-01-19)

  • Add filter_filterLabel to support filter input ARIA labels. 
  • Change filter row role from "row" to "search".
  • Fix select2 issue. 

v2.29.3 (2018-01-11)

  • Network parsers now return a text value. 

v2.29.2 (2017-12-14)

  • Fix non-typical use of selectorHeaders.
  • Update external header icons on sort.
  • Remove an empty block.
  • Select exact matches ignore "and" and "or" keywords.
  • addLastColumn stops adding handles to hidden columns.
  • Adjust columns on filterInit. 
  • New widget added. 

v2.29.0 (2017-09-28)

  • Include callback method for "applyWidgets".
  • Add "widgetRemoveEnd" event. 
  • Clarify warning message (widget enabled but code not loaded).
  • Target header cells for data-column.
  • Add classHasSpan option.
  • Fix compatibility with grouping widget.
  • Fix compatibility with columnSelector widget.
  • Modify internal process function to allow outputting of data without adding it to the table.
  • Add resizableComplete event.
  • Save position to fix scroller_upAfterSort: false; The current position is now saved on scroll so it can be restored after sorting;
  • Update scroll position after fixing columns.
  • Prevent sort2Hash from adding extraneous entries to browser history. Use window.location.replace to update the browser URL only, rather than window.location.hash, which modifies the browser history.
  • Only update class as needed. 
  • Check horizontal scrolling.
  • Remove bootstrap v2 refs & fix docs.
  • Rename icon-white to bootstrap-icon-white. Fixes issue #1432.
  • Update dependencies.
  • Build: maintain ie8 support to fix

v2.28.15 (2017-07-05)

  • Use calculated index instead of DOM index.
  • Fix check count cell indexing.
  • Remove colspan adjustments when widget removed.
  • Include tbody colspan updates on removal.
  • Add namespacing to filter-formatter listeners. Needed to prevent JS error when a "resetToLoadState" is triggered and the "filterFomatterUpdate" bindings are still firing.
  • Fix namespacing of events.
  • Prevent filter update if unchanged & compare (with) hash filter.
  • Fix p's (reference to pager object).
  • ColumnSelector: Add classHasSpan option

v2.28.14 (2017-06-08)

  • Show console error for mismatched column count.
  • (addon) Ensure ajax is called after filter widget init.
  • (addon) Fix height issues for certain browsers (border-spacing).
  • (widget) Apply height adjustment code to pager widget.
  • Use selectorRemove to remove error rows. Removes error rows with dynamically changed class names.

v2.28.13 (2017-06-03)

  • ColumnSelector: Don't clear container on updateAll.
  • Filter: Return null from filter_selectSource to prevent select updates; From discussion in IRC with @alexweissman.
  • Filter: Select searches now process filter types, then exactly match. Previously only exact matches were performed by default, filter types were ignored. This broke the filter + jQuery UI selectmenu demo.

v2.28.10 (2017-05-17)

  • Disable updateCell method for child rows (temporary block until code is fixed).
  • Add namespace class name to table.
  • Prevent input select parser from handling events from child rows.
  • Remove unused variables & add ignoreChildRow option.
  • Bind & update stickyHeaders checkbox.
  • Use correct composer.json jQuery version. 
  • Clarify use of GPLv2 license. 
  • Update dependencies.

v2.28.9 (2017-05-04)

  • Fix widget option changes across multiple tables; seen in the second table of the math page demo with the math_ignore option.
  • Include noop math_complete in defaults; prevents option not recognized warning

v2.28.8 (2017-04-19)

  • Core: Fixed updateCell to work correctly with child rows. 
  • Filter: Add equalFilters function; for more reliable comparisons.
  • Pager: use equalFilters function for comparison. See issue #1384.
  • Resizable: Add resizable_includeFooter option. Fixes issue #1386.
  • Scroller: Set max-width to initial. See issue #1382.
  • Scroller: Fix offset from hidden row. See issue #1376.
  • Scroller: Fix linting issue.
  • Storage: Add options early to prevent validator message.
  • Storage: Add storage_storageType option & deprecate storage_useSessionStorage.
  • Meta: Update dependencies x2.

v2.28.7 (2017-04-12)

  • Editable: Remove "blur" event listeners.
  • Filter: Add "filterAndSortReset" method. 
  • Filter: Prevent JS error added from last update.
  • Meta: Fix composer.json license.

v2.28.0 (2017-04-03)

  • Prevent multiple popups/download with dblClick (i.e. triggering "outputTable" multiple times).
  • Remove extraneous console log.
  • Add "resizableUpdate" & "resizableReset" methods.:
  • Add scrollerComplete event.

v2.17.8 (2014-09-16)

  • Fix widthFixed option to ignore info block tbodies.
  • Make emptyTo & stringTo settings case insensitive.
  • An empty string headerTemplate option will now prevent adding an inner div to the header.
  • Fix setting active accordion from hash script.
  • Add emptyTo clarification.
  • Main readme: Add related projects section.
  • Autoresort true no longer breaks the table.
  • Update demo to use row id instead of index.
  • Update validate function to allow setting it per column.
  • Add editable_focus, editable_blur and editable_selectAll options. See issue #708.
  • Add editable_wrapContent option.
  • Add editable_trimContent option.
  • Validate function now includes a contenteditable element parameter.
  • All text callback parameters are now trimmed.
  • Trim everything & revert widget changes.
  • Refocus edited element after resort only.
  • Switch form focus to focusout.
  • Add filter_defaultFilter option.
  • Add filter_excludeFilter option; add multiple exclusions separated by spaces, not commas.
  • Prevent multiple searches during initialization.
  • Ensure initial filter settings get applied.
  • Selects will exactly match the selected option unless "filter-match" class is set. 
  • Update cache & rows copy. Fixes issue #703.
  • Use native javascript to populate & set the goto select. Fixes issue #711.
  • Custom pager controls. Fix control updates for multiple tables.
  • Fix pager widget to be properly applied after a page move.
  • StickyHeaders: Fix issue so it works with jQuery v1.2.6 again.
  • Zebra: Apply style to one row. 
  • Parser update.

v2.17.7 (2014-08-10)

  • Update.

v2.17.6 (2014-08-02)

  • Adding a class name of parser-false to a column will now automatically set sorter-false and filter-false behavior.
  • Add extractor type which allows giving a column two parsers, one to extract content from an input/select and the second to parse the extracted text. Thanks to TheSin-!
  • Ensure custom parsed data adheres to the ignoreCase option.
  • Add a delay to any sort if there is an update in progress. This prevents issues with a sort being applied causing duplicate rows to be added to the table, hopefully.
  • The widthFixed option now finds both visible th and td cells within the first row of the tbody to set column width percentages.
  • Ensure all rows have a set role for screen readers (role="row"). Fixes issue #690.
  • Redefine c.$headers when building headers for new/replaced header cells (not just content). 
  • Fixed lots of minor HTML issues.
  • Add parser for textareas within the parser-input-select.js file.
  • Modify input & textarea parser to only update the table cache.
  • Add two new options: editable_autoAccept and editable_validate.
  • Modify editable_columns type check to prevent javascript errors. 
  • Limit the editable_columns array value to columns within the table.
  • Make all options show within the current select when the filter-onlyAvail class is set on a column.
  • Updated & added docs for $.tablesorter.filter.buildSelect function to allow external calls to modify filter select options.
  • Update filter_selectSource to accept arrays instead of a function. This was documented as working, but it wasn't coded until now. Sorry!
  • Add filter_selectSourceSeparator option.
  • The ouput option can now include user modifiable startRow ({startRow:input}) or page ({page:input}) inputs within the output.
  • Update $.tablesorter.addHeaderResizeEvent function's first parameter table to accept table DOM elements as well as jQuery objects. 

v2.17.5 (2014-07-04)

  • Add $.tablesorter.hasWidget(table, 'widgetId') function. It returns a boolean value of true when the named widget is actively applied to the table.

v2.17.4 (2014-07-04)

  • Add $.tablesorter.hasWidget(table, 'widgetId') function. It returns a boolean value of true when the named widget is actively applied to the table.
  • Add filter_searchFiltered option to allow disabling the search of already filtered rows.
  • The filter_initialized flag now gets set appropriately. 
  • Include any column filter in determination of searching already filtered rows. 
  • Add internal config.filteredRows variable. Provides a value of the number of currently filtered (visible) rows. 
  • Add internal config.totalRows variable. Provides a value of the total number of rows in the current table, not including info-tbody rows.
  • Fix change/search event being ignored for selects & filterFormatter extensions.
  • filterInit and filterEnd events now pass config as a parameter.
  • Removed from beta status
  • Filtered rows now equals the total rows when ajaxProcessing returns an array. 
  • Update the config.filteredRows when using ajax to match the internal config.pager.filteredRows. 
  • Widget only: ensure pagerComplete event fires on initialization.
  • Bind mousemove to document instead of table header. Makes resizable handle use consistent with other resizing libraries, as the user would expect. .
  • Add resizable_throttle option to allow throttling of the mousemove/resize event. Set this option to true or a number between 1 and 10 to add a throttling delay. 
  • UITheme: non-existent columns no longer cause a js error. 

v2.17.3 (2014-06-29)

  • update and bugs fix.

v2.17.2 (2014-06-19)

  • update and bugs fix.

v2.16.4 (2014-05-05)

  • update

v2.16.3 (2014-05-01)

  • update

v2.15.14 (2014-04-10)

  • Modified bower.json to allow "read-components" compatibility. 
  • Corrected docs
  • Core: Destroy method update
  • See this Stackoverflow question for why this change was made.
  • Grouping widget: group name now saves after callback. 
  • Pager processAjaxOnInit now works with jQuery objects.
  • Filter widget: getFilters will not cause a js error when it targets a non-tablesorter table.

v2.15.13 (2014-04-04)

  • Fix widgets not being applied after an update.
  • Ignore child row class name if it is the first table row
  • Filter widget ignores info tbodies again. Fixes issue #568
  • Docs: show resizable widget update
  • Bootstrap theme:
  • Fix zebra highlighting for child rows

v2.15.12 (2014-03-19)

  • Prevents an error in IE8
  • Fixed merge issues, then modified code to minize use of this indexing
  • Cell column property has correct value again.
  • Replaced references to cell.cellIndex with $(cell).index()
  • Fix docs so nested accordions open with hash.
  • Added tablesorter-hasChildRow class name to all parents of child rows.
  • Added .tablesorter .filtered { display: none; } to every included theme; needed to properly hide child rows
  • Fixed pager so that if the last pager row has any child rows, they are now included. 
  • Add resizable_widths option

v2.15.11 (2014-03-19)

  • Updated Bootstrap to v3.1.1
  • Check if cell has parser to catch undefined error.
  • Column count is now correct with nested tables (with tfoot).
  • Fix table reset on pagination change.

v2.15.10 (2014-03-14)

  • Fix numberSorter option causing a javascript error & added test.

v2.15.9 (2014-03-13)

  • Filter formatter (jQuery UI) work again

v2.15.6 (2014-03-08)

  • cleanup & version bump

v2.15.3 (2014-02-22)

  • updated to the latest version.

v2.15.2 (2014-02-21)

  • updated to the latest version.

v2.15.1 (2014-02-20)

  • updated to the latest version.

v2.14.3 (2013-12-17)

  • updated to the latest version.

v2.14.2 (2013-12-03)

  • updated to the latest version.

v2.14.1 (2013-11-23)

  • updated to the latest version.

v2.14.0 (2013-11-20)

  • updated to the latest version.

v2.13.3 (2013-11-10)

  • updated to the latest version.

v2.13.0 (2013-10-31)

  • Bugs fixed.
  • Added pager countChildRows option (plugin & widget)
  • Added a file-type parser
  • Updated LESS theme to work properly with LESS 4.1+

v2.12.0 (2013-10-19)

  • Added fixedUrl option for use with the widget storage function. 

v2.11.1 (2013-10-12)

  • bugs fixed

v2.10.8 (2013-06-05)

  • Updated the percent parser to only detect if the content is shorter than 15 characters. This prevents columns with a lot of content and one percent sign (%) from being set to be parsed as a percent numeric column. Fixes issue #320.
  • Updated filter widget & filter_formatter
  • Fixed stickyHeaders widget

v2.10.7 (2013-06-01)

  • Fixed Issue with updateCell Event with Multiple tbody's on Page

v2.10.6 (2013-05-31)

  • Added skipTest options to the HTML5 filter formatter functions. Fixed html5Number doesn't work on FF 20/21
  • Fixed filter_formatter and stickyHeaders
  • Fixed stickyHeader filter value issue

v2.10.4 (2013-05-29)

  • Added stickyHeadersInit event, which is triggered on the table after the sticky headers widget has completed initializing.
  • Filtering child rows should now work properly.

v2.10.3 (2013-05-27)

  • Updated pager pageSize method to properly store the set page size

v2.10.0 (2013-05-09)

  • Features updated and bugs fixed

v2.9.1 (2013-04-14)

  • fixes stickyHeader widget lag

v2.8.2 (2013-04-13)

  • Updated the "ignore-leads" parser
  • Fixed a bug in the grouping widget demo

v2.8.2 (2013-03-29)

  • Updated the "ignore-leads" parser

v2.8.1 (2013-03-28)

  • Added customAjaxUrl option to the pager

v2.8.0 (2013-03-28)

  • More features updated and bugs fixed.

v2.7.12 (2013-03-01)

  • Fixed hiding filter rows when using filter_formatter elements. 
  • Fixed an issue with updateCell method not removing extra table rows before computing the row index of the cell that was just updated.
  • Added an exactMatch option to the html5color filter_formatter function.
  • Added missing documentation for the updateCell callback method. It's been there for a while!

This awesome jQuery plugin is developed by Mottie. For more Advanced Usages, please check the demo page or visit the official website.