Ok, I tried to create code for your problem. This is not the best way to do this, but it seems to have worked. Let me know if this is good for you, and if so, if you are fine, to implement it the way you want.
I will try to improve it and turn it into a jQuery plugin:
http://jsfiddle.net/chambs/TRnP7
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); var data = [ {name: 'Alice', zip: '14124', pet: 'Squirrel'}, {name: 'Alfred', zip: '24601', pet: 'Meerkat'}, {name: 'Anupam', zip: '91532', pet: 'Gila monster'}, {name: 'Bernice', zip: '03413', pet: 'Rock'}, {name: 'Boris', zip: '32610', pet: 'Fish'}, {name: 'Betty', zip: '71011', pet: 'Elephant'} ]; var lastType = ''; function getHeader() { var row = this[0], header = []; for(var k in row) { header.push(k); } return header; } function sortBy(criteria) { lastType = criteria; var c = criteria || 'name'; return this.sort(function(a, b) { return a[c] > b[c]; }); } function render(tbl, data) { tbl.empty(); var buffer = "<tr><th class='letter'> </th>", header = getHeader.call(data); for(var i=0; i < header.length; i++) { buffer += "<th class='sort' data-type='"+header[i]+"'>"+header[i]+"</th>"; } buffer += "</tr>"; tbl.append(buffer); buffer = ""; for(var i=0; i < data.length; i++) { var l = data[i].name.substr(0, 1); buffer += "<tr><td class='"+l+"'>" + l + "</td>"; for(var j=0; j < header.length; j++) { var k = header[j]; buffer += "<td>" + data[i][k] + "</td>"; } buffer += "</tr>"; tbl.append(buffer); buffer = ""; } if(lastType === 'name') { merge(tbl); } } function merge(tbl) { for(var i=0; i < letters.length; i++) { var l = letters[i]; var td = $('.' + l, tbl); if(td.length > 1) { td.eq(0).attr('rowspan', td.length); $('.' + l + ':gt(0)', tbl).remove(); } } } sortBy.call(data, 'name'); render($('#tbl'), data); $(document).on('click', '.sort', function(ev) { var type = $(this).data('type'); sortBy.call(data, type); render($('#tbl'), data); });