User Management Table Layout Component
A comprehensive user management interface featuring a responsive table to display user data. It includes fully integrated and interactive "Edit" and "Delete" modals for CRUD operations, with dynamic status and role badges.
LTR
RTL
<div class="container mx-auto px-4 py-8" x-data="{
darkMode: false,
rtlMode: false,
showEditModal: false,
showDeleteModal: false,
editingIndex: -1,
deletingIndex: -1,
editingUser: {},
deletingUser: {},
users: [
{
id: 1,
name: 'Jane Cooper',
email: 'jane.cooper@example.com',
role: 'Admin',
status: 'Active',
avatar: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60'
},
{
id: 3,
name: 'Esther Howard',
email: 'esther.howard@example.com',
role: 'User',
status: 'Inactive',
avatar: 'https://images.unsplash.com/photo-1520813792240-56fc4a3765a7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60'
},
{
id: 4,
name: 'Jenny Wilson',
email: 'jenny.wilson@example.com',
role: 'User',
status: 'Pending',
avatar: 'https://images.unsplash.com/photo-1498551172505-8ee7ad69f235?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60'
},
{
id: 5,
name: 'Robert Fox',
email: 'robert.fox@example.com',
role: 'Editor',
status: 'Active',
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60'
}
],
init() {
this.darkMode = localStorage.getItem('darkMode') === 'true';
this.rtlMode = localStorage.getItem('rtlMode') === 'true';
},
toggleDarkMode() {
this.darkMode = !this.darkMode;
localStorage.setItem('darkMode', this.darkMode);
},
toggleRtlMode() {
this.rtlMode = !this.rtlMode;
localStorage.setItem('rtlMode', this.rtlMode);
},
getRoleClass(role) {
return role === 'Admin' ? 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200' :
role === 'Editor' ? 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200' :
'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200';
},
getStatusClass(status) {
return status === 'Active' ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' :
status === 'Inactive' ? 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' :
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200';
},
editUser(index) {
this.editingIndex = index;
this.editingUser = {...this.users[index]};
this.showEditModal = true;
},
saveEdit() {
if (this.editingIndex !== -1) {
this.users[this.editingIndex] = {...this.editingUser};
}
this.showEditModal = false;
this.editingIndex = -1;
this.editingUser = {};
},
deleteUser(index) {
this.deletingIndex = index;
this.deletingUser = {...this.users[index]};
this.showDeleteModal = true;
},
confirmDelete() {
if (this.deletingIndex !== -1) {
this.users.splice(this.deletingIndex, 1);
}
this.showDeleteModal = false;
this.deletingIndex = -1;
this.deletingUser = {};
}
}">
<!-- Header with Controls -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 gap-4">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">User Management</h1>
<p class="text-gray-600 dark:text-gray-400">Manage your users with edit and delete actions</p>
</div>
</div>
<!-- Table Container -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden transition-colors duration-300">
<!-- Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th scope="col" class="px-6 py-3 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Name</th>
<th scope="col" class="px-6 py-3 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Email</th>
<th scope="col" class="px-6 py-3 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Role</th>
<th scope="col" class="px-6 py-3 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Status</th>
<th scope="col" class="px-6 py-3 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
<template x-for="(user, index) in users" :key="user.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" :src="user.avatar" alt="">
</div>
<div class="ml-4 rtl:ml-0 rtl:mr-4">
<div class="text-sm font-medium text-gray-900 dark:text-white" x-text="user.name"></div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900 dark:text-white" x-text="user.email"></div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full"
x-bind:class="getRoleClass(user.role)" x-text="user.role"></span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full"
x-bind:class="getStatusClass(user.status)" x-text="user.status"></span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex space-x-2 rtl:space-x-reverse">
<button x-on:click="editUser(index)"
class="text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 transition-colors">
Edit
</button>
<button x-on:click="deleteUser(index)"
class="text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 transition-colors">
Delete
</button>
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- Edit Modal -->
<div x-show="showEditModal" class="fixed inset-0 overflow-y-auto z-50" style="display: none;">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
<div>
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white mb-4">
Edit User
</h3>
<div class="mb-4">
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Name</label>
<input type="text" id="name" x-model="editingUser.name" class="mt-1 block w-full border border-gray-300 dark:border-gray-600 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white">
</div>
<div class="mb-4">
<label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Email</label>
<input type="email" id="email" x-model="editingUser.email" class="mt-1 block w-full border border-gray-300 dark:border-gray-600 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white">
</div>
<div class="mb-4">
<label for="role" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Role</label>
<select id="role" x-model="editingUser.role" class="mt-1 block w-full border border-gray-300 dark:border-gray-600 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white">
<option value="Admin">Admin</option>
<option value="User">User</option>
<option value="Editor">Editor</option>
</select>
</div>
<div class="mb-4">
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Status</label>
<select id="status" x-model="editingUser.status" class="mt-1 block w-full border border-gray-300 dark:border-gray-600 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white">
<option value="Active">Active</option>
<option value="Inactive">Inactive</option>
<option value="Pending">Pending</option>
</select>
</div>
</div>
<div class="mt-5 sm:mt-6 sm:grid sm:grid-cols-2 sm:gap-3 sm:grid-flow-row-dense">
<button type="button" x-on:click="saveEdit" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:col-start-2 sm:text-sm">
Save
</button>
<button type="button" x-on:click="showEditModal = false" class="mt-3 sm:mt-0 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-600 shadow-sm px-4 py-2 bg-white dark:bg-gray-700 text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:col-start-1 sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div x-show="showDeleteModal" class="fixed inset-0 overflow-y-auto z-50" style="display: none;">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<svg class="h-6 w-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left rtl:sm:ml-0 rtl:sm:mr-4">
<h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white">
Delete User
</h3>
<div class="mt-2">
<p class="text-sm text-gray-500 dark:text-gray-400">
Are you sure you want to delete <span x-text="deletingUser.name" class="font-medium"></span>? This action cannot be undone.
</p>
</div>
</div>
</div>
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button type="button" x-on:click="confirmDelete" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
Delete
</button>
<button type="button" x-on:click="showDeleteModal = false" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-600 shadow-sm px-4 py-2 bg-white dark:bg-gray-700 text-base font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:mt-0 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
</div>