JSFiddle - React, Tailwind, and code Playground

by Michael Prosser

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<table width="100%" border="0" cellspacing="0" cellpadding="5"><tbody class="task-data-headers"><tr><th>Name</th><th>Date</th><th>Time</th><th>Recurrence</th><th>Due Date</th><th>Facility</th><th>Owner</th><th>Description</th><th>Type</th><th>Service</th><th>Scope</th><th>Comments</th></tr></tbody><tbody class="task-data-rows"><tr title="Double-Click to edit this record" data-config-length="3" data-date="2023-10-03" data-task-id="1139" class="original completed" data-event-type="task"><td>New Task</td><td>2023-10-03</td><td>00:00:00</td><td>every-week</td><td>2023-10-24</td><td>Global</td><td>Michael Prosser</td><td></td><td>The cat</td><td>agPROACTIVE</td><td>Maintenance Forms</td><td></td></tr><tr title="Double-Click to edit this record" data-config-length="3" data-date="2023-11-07" data-task-id="1139" data-event-type="task"><td>New Task</td><td>2023-11-07</td><td>00:00:00</td><td>every-week</td><td>2023-11-28</td><td>Global</td><td>Michael Prosser</td><td></td><td>The cat</td><td>agPROACTIVE</td><td>Maintenance Forms</td><td></td></tr><tr title="Double-Click to edit this record" data-config-length="3" data-date="2023-11-14" data-task-id="1139" data-event-type="task"><td>New Task</td><td>2023-11-14</td><td>00:00:00</td><td>every-week</td><td>2023-12-05</td><td>Global</td><td>Michael Prosser</td><td></td><td>The cat</td><td>agPROACTIVE</td><td>Maintenance Forms</td><td></td></tr><tr title="Double-Click to edit this record" data-config-length="3" data-date="2023-11-21" data-task-id="1139" data-event-type="task"><td>New Task</td><td>2023-11-21</td><td>00:00:00</td><td>every-week</td><td>2023-12-12</td><td>Global</td><td>Michael Prosser</td><td></td><td>The cat</td><td>agPROACTIVE</td><td>Maintenance Forms</td><td></td></tr><tr title="Double-Click to edit this record" data-config-length="3" data-date="2023-11-28" data-task-id="1139" data-event-type="task"><td>New...

CSS

table{
  font-family: helvetica;
}
table th {
    font-size: 12px;
    font-weight: bold;
    color: #000;
    background-color: #FFF;
    text-align: left;
}
table>tbody>tr>th {
    background-color: #356DB0 !important;
    color: #ffffff !important;
    white-space: nowrap;
}
table>tbody>tr>th[data-sort-order="ASC"]:after{
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 5px 5px 0 5px;
  border-color: #ffffff transparent transparent transparent;
  margin-left: 5px;
  vertical-align: middle;
  white-space: nowrap;
}
table>tbody>tr>th[data-sort-order="DESC"]:after{
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 5px 5px 5px;
  border-color: transparent transparent #ffffff transparent;
  margin-left: 5px;
  vertical-align: middle;
  white-space: nowrap;
}
table tbody.task-data-rows>tr>td {
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    width: auto;
    border: solid 1px #eee;
    height: auto !important;
    vertical-align: top;
    position: relative;
    overflow: visible;
    cursor: pointer;
}

JavaScript

function Sortable(headerTableBodyElement,contentTableBodyElement){

	var t = this;

	t.sortOrder = 'ASC';
	t.sortColumn = '';
	t.sortColumnIndex = -1;
  
  headerTableBodyElement.find('th').attr('data-sort-order','');

	headerTableBodyElement.find('th').click(function(){
  
  	headerTableBodyElement.find('th').attr('data-sort-order','');
  
  	if(t.sortColumnIndex == $(this).index()){
    
    	if(t.sortOrder == 'ASC'){
    
        t.sortOrder = 'DESC';

      } else {

        t.sortOrder = 'ASC';

      }
    
    } else {
    
    	t.sortOrder = 'ASC';
      t.sortColumn = $(this).text();
      t.sortColumnIndex = $(this).index();
    
    }
    
    console.log(t);
    
    headerTableBodyElement.find('th').eq(t.sortColumnIndex).attr('data-sort-order',t.sortOrder);
    
    t.sort();
  	
  });
  
  t.sort = function(){
  
  	// store original elements in an array for comparison
    
    var tr = [];
    var search = [];
  
  	contentTableBodyElement.find('tr').each(function(index){
    
    	tr.push({
      
      	element: $(this),
        index: index
      
      });
      
      search.push({
      	value: $(this).find('td').eq(t.sortColumnIndex).text(),
        element: $(this)
      });
    
    });
    
    if(t.sortOrder == 'ASC'){
    
    	search.sort(function(a, b) {
        var keyA = a.value,
            keyB = b.value;
        // Compare the 2 dates
        if (keyA < keyB) return -1;
        if (keyA > keyB) return 1;
        return 0;
      });
    
    } else {
    
    	search.sort(function(a, b) {
        var keyA = a.value,
            keyB = b.value;
        // Compare the 2 dates
        if (keyA < keyB) return -1;
        if (keyA > keyB) return 1;
        return 0;
      }).reverse();
    
    }
    
    for(var i=0;i<search.length;i++){
    
    	search[i].detached = search[i].element.detach();
    
    }
    
    for(var i=0;i<search.length;i++){

    	contentTableBodyElement.append(search[i].detached);
    
    }
    
   ...