<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 60px 0;
}
.table-container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.table-header {
margin-bottom: 30px;
}
.table-header h2 {
font-size: 2rem;
font-weight: 700;
color: #2c3e50;
margin-bottom: 10px;
}
.table-header p {
color: #7f8c8d;
margin-bottom: 0;
}
/* Search and Filter Section */
.table-controls {
display: flex;
justify-content: space-between;
align-items: center;
gap: 15px;
margin-bottom: 25px;
flex-wrap: wrap;
}
.search-box {
position: relative;
flex: 1;
min-width: 250px;
}
.search-input {
width: 100%;
padding: 12px 45px 12px 20px;
border: 2px solid #e0e0e0;
border-radius: 50px;
transition: all 0.3s ease;
font-size: 0.95rem;
}
.search-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.15);
}
.search-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
color: #7f8c8d;
}
.entries-select {
padding: 10px 35px 10px 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-weight: 600;
color: #2c3e50;
cursor: pointer;
transition: all 0.3s ease;
}
.entries-select:focus {
outline: none;
border-color: #667eea;
}
/* Table Styles */
.custom-table {
margin-bottom: 0;
}
.custom-table thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.custom-table thead th {
color: white;
font-weight: 600;
padding: 15px;
border: none;
text-transform: uppercase;
font-size: 0.85rem;
letter-spacing: 0.5px;
cursor: pointer;
position: relative;
user-select: none;
}
.custom-table thead th:hover {
background: rgba(255, 255, 255, 0.1);
}
.custom-table thead th.sortable::after {
content: '⇅';
position: absolute;
right: 10px;
opacity: 0.5;
}
.custom-table thead th.sorted-asc::after {
content: '↑';
opacity: 1;
}
.custom-table thead th.sorted-desc::after {
content: '↓';
opacity: 1;
}
.custom-table tbody tr {
transition: all 0.3s ease;
border-bottom: 1px solid #e0e0e0;
}
.custom-table tbody tr:hover {
background: #f8f9fa;
transform: scale(1.01);
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
}
.custom-table tbody td {
padding: 18px 15px;
color: #2c3e50;
vertical-align: middle;
}
.custom-table tbody tr:last-child {
border-bottom: none;
}
/* Status Badge */
.status-badge {
padding: 6px 14px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
display: inline-block;
}
.status-badge.active {
background: #d4edda;
color: #155724;
}
.status-badge.inactive {
background: #f8d7da;
color: #721c24;
}
.status-badge.pending {
background: #fff3cd;
color: #856404;
}
/* Action Buttons */
.action-btn {
padding: 6px 12px;
border: none;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin: 0 3px;
}
.action-btn.edit {
background: #667eea;
color: white;
}
.action-btn.edit:hover {
background: #5568d3;
transform: translateY(-2px);
}
.action-btn.delete {
background: #e74c3c;
color: white;
}
.action-btn.delete:hover {
background: #c0392b;
transform: translateY(-2px);
}
/* Pagination */
.table-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 25px;
flex-wrap: wrap;
gap: 15px;
}
.table-info {
color: #7f8c8d;
font-size: 0.9rem;
}
.pagination {
margin: 0;
}
.page-link {
border: 2px solid #e0e0e0;
color: #2c3e50;
padding: 8px 16px;
margin: 0 3px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
}
.page-link:hover {
background: #667eea;
border-color: #667eea;
color: white;
transform: translateY(-2px);
}
.page-item.active .page-link {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: transparent;
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.page-item.disabled .page-link {
opacity: 0.5;
cursor: not-allowed;
}
/* No Results Message */
.no-results {
text-align: center;
padding: 40px;
color: #7f8c8d;
display: none;
}
.no-results.show {
display: block;
}
.no-results-icon {
font-size: 3rem;
margin-bottom: 15px;
opacity: 0.5;
}
/* Responsive */
@media (max-width: 768px) {
.table-container {
padding: 20px;
}
.custom-table {
font-size: 0.85rem;
}
.custom-table thead th,
.custom-table tbody td {
padding: 10px 8px;
}
.table-controls {
flex-direction: column;
}
.search-box {
width: 100%;
}
}
/* Loading Animation */
.loading {
display: none;
text-align: center;
padding: 40px;
}
.loading.show {
display: block;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class="container">
<div class="table-container">
<!-- Table Header -->
<div class="table-header">
<h2>Employee Directory</h2>
<p>Manage and view employee information</p>
</div>
<!-- Search and Controls -->
<div class="table-controls">
<div class="search-box">
<input
type="text"
class="search-input"
id="searchInput"
placeholder="Search by name, email, or department..."
>
<span class="search-icon">🔍</span>
</div>
<div>
<label for="entriesSelect" class="me-2">Show:</label>
<select class="entries-select" id="entriesSelect">
<option value="5">5 entries</option>
<option value="10" selected>10 entries</option>
<option value="25">25 entries</option>
<option value="50">50 entries</option>
</select>
</div>
</div>
<!-- Table -->
<div class="table-responsive">
<table class="table custom-table">
<thead>
<tr>
<th class="sortable" data-column="id">#</th>
<th class="sortable" data-column="name">Name</th>
<th class="sortable" data-column="email">Email</th>
<th class="sortable" data-column="department">Department</th>
<th class="sortable" data-column="position">Position</th>
<th class="sortable" data-column="status">Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="tableBody">
<!-- Data will be inserted here -->
</tbody>
</table>
<!-- No Results Message -->
<div class="no-results" id="noResults">
<div class="no-results-icon">🔍</div>
<h4>No results found</h4>
<p>Try adjusting your search criteria</p>
</div>
</div>
<!-- Pagination -->
<div class="table-footer">
<div class="table-info" id="tableInfo">
Showing 1 to 10 of 50 entries
</div>
<nav>
<ul class="pagination" id="pagination">
<!-- Pagination buttons will be inserted here -->
</ul>
</nav>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
// Sample data
const employeeData = [
{ id: 1, name: 'John Doe', email: 'john.doe@company.com', department: 'Engineering', position: 'Software Engineer', status: 'active' },
{ id: 2, name: 'Jane Smith', email: 'jane.smith@company.com', department: 'Marketing', position: 'Marketing Manager', status: 'active' },
{ id: 3, name: 'Mike Johnson', email: 'mike.johnson@company.com', department: 'Sales', position: 'Sales Representative', status: 'pending' },
{ id: 4, name: 'Sarah Williams', email: 'sarah.williams@company.com', department: 'HR', position: 'HR Manager', status: 'active' },
{ id: 5, name: 'David Brown', email: 'david.brown@company.com', department: 'Engineering', position: 'Senior Developer', status: 'active' },
{ id: 6, name: 'Emily Davis', email: 'emily.davis@company.com', department: 'Design', position: 'UI/UX Designer', status: 'inactive' },
{ id: 7, name: 'Robert Miller', email: 'robert.miller@company.com', department: 'Finance', position: 'Financial Analyst', status: 'active' },
{ id: 8, name: 'Lisa Wilson', email: 'lisa.wilson@company.com', department: 'Marketing', position: 'Content Writer', status: 'pending' },
{ id: 9, name: 'James Taylor', email: 'james.taylor@company.com', department: 'Engineering', position: 'DevOps Engineer', status: 'active' },
{ id: 10, name: 'Maria Garcia', email: 'maria.garcia@company.com', department: 'Sales', position: 'Account Executive', status: 'active' },
{ id: 11, name: 'Thomas Anderson', email: 'thomas.anderson@company.com', department: 'HR', position: 'Recruiter', status: 'active' },
{ id: 12, name: 'Jessica Martinez', email: 'jessica.martinez@company.com', department: 'Design', position: 'Graphic Designer', status: 'inactive' },
{ id: 13, name: 'Christopher Lee', email: 'chris.lee@company.com', department: 'Engineering', position: 'Tech Lead', status: 'active' },
{ id: 14, name: 'Amanda White', email: 'amanda.white@company.com', department: 'Marketing', position: 'Social Media Manager', status: 'pending' },
{ id: 15, name: 'Daniel Harris', email: 'daniel.harris@company.com', department: 'Finance', position: 'Accountant', status: 'active' },
{ id: 16, name: 'Michelle Clark', email: 'michelle.clark@company.com', department: 'Sales', position: 'Sales Manager', status: 'active' },
{ id: 17, name: 'Matthew Lewis', email: 'matthew.lewis@company.com', department: 'Engineering', position: 'QA Engineer', status: 'active' },
{ id: 18, name: 'Ashley Walker', email: 'ashley.walker@company.com', department: 'HR', position: 'HR Specialist', status: 'inactive' },
{ id: 19, name: 'Joshua Hall', email: 'joshua.hall@company.com', department: 'Design', position: 'Product Designer', status: 'active' },
{ id: 20, name: 'Stephanie Allen', email: 'stephanie.allen@company.com', department: 'Marketing', position: 'SEO Specialist', status: 'pending' }
];
let currentPage = 1;
let entriesPerPage = 10;
let filteredData = [...employeeData];
let sortColumn = null;
let sortDirection = 'asc';
// Initialize
function init() {
renderTable();
setupEventListeners();
}
// Setup event listeners
function setupEventListeners() {
document.getElementById('searchInput').addEventListener('input', handleSearch);
document.getElementById('entriesSelect').addEventListener('change', handleEntriesChange);
// Sort functionality
document.querySelectorAll('.sortable').forEach(th => {
th.addEventListener('click', () => handleSort(th.dataset.column));
});
}
// Handle search
function handleSearch(e) {
const searchTerm = e.target.value.toLowerCase();
filteredData = employeeData.filter(emp =>
emp.name.toLowerCase().includes(searchTerm) ||
emp.email.toLowerCase().includes(searchTerm) ||
emp.department.toLowerCase().includes(searchTerm) ||
emp.position.toLowerCase().includes(searchTerm)
);
currentPage = 1;
renderTable();
}
// Handle entries per page change
function handleEntriesChange(e) {
entriesPerPage = parseInt(e.target.value);
currentPage = 1;
renderTable();
}
// Handle sorting
function handleSort(column) {
if (sortColumn === column) {
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
} else {
sortColumn = column;
sortDirection = 'asc';
}
filteredData.sort((a, b) => {
let aVal = a[column];
let bVal = b[column];
if (typeof aVal === 'string') {
aVal = aVal.toLowerCase();
bVal = bVal.toLowerCase();
}
if (sortDirection === 'asc') {
return aVal > bVal ? 1 : -1;
} else {
return aVal < bVal ? 1 : -1;
}
});
// Update sort indicators
document.querySelectorAll('.sortable').forEach(th => {
th.classList.remove('sorted-asc', 'sorted-desc');
});
const sortedTh = document.querySelector(`[data-column="${column}"]`);
sortedTh.classList.add(sortDirection === 'asc' ? 'sorted-asc' : 'sorted-desc');
renderTable();
}
// Render table
function renderTable() {
const tableBody = document.getElementById('tableBody');
const noResults = document.getElementById('noResults');
if (filteredData.length === 0) {
tableBody.innerHTML = '';
noResults.classList.add('show');
document.getElementById('tableInfo').textContent = 'No entries to show';
document.getElementById('pagination').innerHTML = '';
return;
}
noResults.classList.remove('show');
const startIndex = (currentPage - 1) * entriesPerPage;
const endIndex = Math.min(startIndex + entriesPerPage, filteredData.length);
const pageData = filteredData.slice(startIndex, endIndex);
tableBody.innerHTML = pageData.map(emp => `
<tr>
<td>${emp.id}</td>
<td>${emp.name}</td>
<td>${emp.email}</td>
<td>${emp.department}</td>
<td>${emp.position}</td>
<td><span class="status-badge ${emp.status}">${emp.status.charAt(0).toUpperCase() + emp.status.slice(1)}</span></td>
<td>
<button class="action-btn edit" onclick="editEmployee(${emp.id})">Edit</button>
<button class="action-btn delete" onclick="deleteEmployee(${emp.id})">Delete</button>
</td>
</tr>
`).join('');
updatePagination();
updateTableInfo(startIndex, endIndex);
}
// Update pagination
function updatePagination() {
const totalPages = Math.ceil(filteredData.length / entriesPerPage);
const pagination = document.getElementById('pagination');
let paginationHTML = '';
// Previous button
paginationHTML += `
<li class="page-item ${currentPage === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="changePage(${currentPage - 1}); return false;">Previous</a>
</li>
`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
if (i === 1 || i === totalPages || (i >= currentPage - 1 && i <= currentPage + 1)) {
paginationHTML += `
<li class="page-item ${i === currentPage ? 'active' : ''}">
<a class="page-link" href="#" onclick="changePage(${i}); return false;">${i}</a>
</li>
`;
} else if (i === currentPage - 2 || i === currentPage + 2) {
paginationHTML += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
}
}
// Next button
paginationHTML += `
<li class="page-item ${currentPage === totalPages ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="changePage(${currentPage + 1}); return false;">Next</a>
</li>
`;
pagination.innerHTML = paginationHTML;
}
// Update table info
function updateTableInfo(startIndex, endIndex) {
const tableInfo = document.getElementById('tableInfo');
tableInfo.textContent = `Showing ${startIndex + 1} to ${endIndex} of ${filteredData.length} entries`;
}
// Change page
function changePage(page) {
const totalPages = Math.ceil(filteredData.length / entriesPerPage);
if (page < 1 || page > totalPages) return;
currentPage = page;
renderTable();
}
// Action functions (demo)
function editEmployee(id) {
alert(`Edit employee with ID: ${id}`);
}
function deleteEmployee(id) {
if (confirm(`Are you sure you want to delete employee with ID: ${id}?`)) {
const index = employeeData.findIndex(emp => emp.id === id);
if (index > -1) {
employeeData.splice(index, 1);
filteredData = [...employeeData];
renderTable();
}
}
}
// Initialize on load
init();
</script>
Login to leave a comment
Login
No comments yet. Be the first!