Component
Sortable Table
Employee directory table with interactive column sorting. Click any column header to sort data. Supports alphabetical, numeric, and custom data sorting with visual feedback.
- Component
- Tailwind
- HTML
- MIT
Preview
Live component
9:41 100%
devsnips.dev/library/tailwind/components/tables/sortable-table/ fluid · no fixed width 100%
Install
Add to your project
npx devsnips add Tailwind/Components/Tables/sortable-table Tailwind/Components/Tables/sortable-table <div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-x-auto">
<table class="w-full min-w-[640px]" id="sortableTable">
<thead>
<tr class="bg-gray-50 border-b border-gray-200">
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(0)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Employee
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(1)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Department
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(2)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Salary
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(3)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Performance
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(4)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Experience
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
<th class="px-5 py-3.5 text-left">
<button onclick="sortTable(5)" class="flex items-center gap-2 text-xs font-bold text-gray-600 uppercase tracking-wider hover:text-gray-900 group">
Status
<svg class="w-4 h-4 text-gray-400 group-hover:text-gray-600 transition-colors sort-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100" id="tableBody">
<tr class="hover:bg-gray-50 transition-colors" data-salary="145000" data-performance="92" data-experience="8">
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop" alt="James Wilson" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="text-sm font-medium text-gray-900">James Wilson</p>
<p class="text-xs text-gray-500">j.wilson@company.com</p>
</div>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">Engineering</td>
<td class="px-5 py-4 text-sm font-semibold text-gray-900">$145,000</td>
<td class="px-5 py-4">
<div class="flex items-center gap-2">
<div class="w-20 h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-emerald-500 rounded-full" style="width: 92%"></div>
</div>
<span class="text-sm font-medium text-emerald-600">92%</span>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">8 years</td>
<td class="px-5 py-4">
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-emerald-100 text-emerald-700">Active</span>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors" data-salary="125000" data-performance="88" data-experience="5">
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop" alt="Sarah Chen" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="text-sm font-medium text-gray-900">Sarah Chen</p>
<p class="text-xs text-gray-500">s.chen@company.com</p>
</div>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">Product</td>
<td class="px-5 py-4 text-sm font-semibold text-gray-900">$125,000</td>
<td class="px-5 py-4">
<div class="flex items-center gap-2">
<div class="w-20 h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-emerald-500 rounded-full" style="width: 88%"></div>
</div>
<span class="text-sm font-medium text-emerald-600">88%</span>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">5 years</td>
<td class="px-5 py-4">
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-emerald-100 text-emerald-700">Active</span>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors" data-salary="95000" data-performance="76" data-experience="3">
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<img src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop" alt="Michael Park" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="text-sm font-medium text-gray-900">Michael Park</p>
<p class="text-xs text-gray-500">m.park@company.com</p>
</div>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">Design</td>
<td class="px-5 py-4 text-sm font-semibold text-gray-900">$95,000</td>
<td class="px-5 py-4">
<div class="flex items-center gap-2">
<div class="w-20 h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-amber-500 rounded-full" style="width: 76%"></div>
</div>
<span class="text-sm font-medium text-amber-600">76%</span>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">3 years</td>
<td class="px-5 py-4">
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-emerald-100 text-emerald-700">Active</span>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors" data-salary="110000" data-performance="84" data-experience="4">
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<img src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop" alt="Emma Thompson" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="text-sm font-medium text-gray-900">Emma Thompson</p>
<p class="text-xs text-gray-500">e.thompson@company.com</p>
</div>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">Marketing</td>
<td class="px-5 py-4 text-sm font-semibold text-gray-900">$110,000</td>
<td class="px-5 py-4">
<div class="flex items-center gap-2">
<div class="w-20 h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-blue-500 rounded-full" style="width: 84%"></div>
</div>
<span class="text-sm font-medium text-blue-600">84%</span>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">4 years</td>
<td class="px-5 py-4">
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-amber-100 text-amber-700">On Leave</span>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors" data-salary="135000" data-performance="90" data-experience="7">
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<img src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop" alt="David Lee" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="text-sm font-medium text-gray-900">David Lee</p>
<p class="text-xs text-gray-500">d.lee@company.com</p>
</div>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">Engineering</td>
<td class="px-5 py-4 text-sm font-semibold text-gray-900">$135,000</td>
<td class="px-5 py-4">
<div class="flex items-center gap-2">
<div class="w-20 h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-emerald-500 rounded-full" style="width: 90%"></div>
</div>
<span class="text-sm font-medium text-emerald-600">90%</span>
</div>
</td>
<td class="px-5 py-4 text-sm text-gray-600">7 years</td>
<td class="px-5 py-4">
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-emerald-100 text-emerald-700">Active</span>
</td>
</tr>
</tbody>
</table>
</div>
<script>
let sortDirection = {};
function sortTable(columnIndex) {
const table = document.getElementById('sortableTable');
const tbody = document.getElementById('tableBody');
const rows = Array.from(tbody.querySelectorAll('tr'));
sortDirection[columnIndex] = !sortDirection[columnIndex];
const direction = sortDirection[columnIndex] ? 1 : -1;
const sortedRows = rows.sort((a, b) => {
let aVal, bVal;
if (columnIndex === 0 || columnIndex === 1 || columnIndex === 5) {
aVal = a.cells[columnIndex].textContent.trim();
bVal = b.cells[columnIndex].textContent.trim();
return aVal.localeCompare(bVal) * direction;
} else if (columnIndex === 2) {
aVal = parseInt(a.dataset.salary);
bVal = parseInt(b.dataset.salary);
} else if (columnIndex === 3) {
aVal = parseInt(a.dataset.performance);
bVal = parseInt(b.dataset.performance);
} else if (columnIndex === 4) {
aVal = parseInt(a.dataset.experience);
bVal = parseInt(b.dataset.experience);
}
return (aVal - bVal) * direction;
});
tbody.innerHTML = '';
sortedRows.forEach(row => tbody.appendChild(row));
document.querySelectorAll('.sort-icon').forEach(icon => {
icon.classList.remove('text-blue-600');
icon.classList.add('text-gray-400');
});
const headerIcons = table.querySelectorAll('th button .sort-icon');
headerIcons[columnIndex].classList.remove('text-gray-400');
headerIcons[columnIndex].classList.add('text-blue-600');
}
</script> # Sortable Table
Table with sortable columns.
## Usage
```bash
npx devsnips add Tailwind/Components/Tables/sortable-table
```
Copy from `code.html`.
## File Structure
`code.html` · `preview.html` · `metadata.json` · `README.md` 228 lines UTF-8 · LF · Spaces: 2
Continue browsing